Abaks: Interface Adapters - API
After the Use Cases there are the Interface Adapters, namely the HTTP (REST) API.
We'll use servant to build a REST API.
Let's start by setting the layout:
type API = NamedRoutes API'
data API' r = API
{ createPeriodAPI :: r :- CreatePeriodAPI,
}
deriving stock (Generic)
We have declare all the endpoints we can define such as:
type CreatePeriodAPI =
Summary "Create a Period"
:> OperationId "createPeriod"
:> ReqBody '[JSON] CreatePeriodRequest
:> Post '[JSON] CreatePeriodResponse
data CreatePeriodRequest = CreatePeriodRequest
{ name :: Text,
}
deriving stock (Generic)
deriving anyclass (FromJSON, ToJSON)
newtype CreatePeriodResponse = CreatePeriodResponse
{ periodId :: Text
}
deriving stock (Eq, Show, Generic)
deriving anyclass (FromJSON, ToJSON)
createPeriodHandler req =
genericUseCaseHandler (CreatePeriodResponse . (.getPeriodId.getAggregateId)) $
UC.createPeriod req.name req.from req.to $
toAmount req.initialBalance
It's actually a naive implementation, especially the error handling:
genericUseCaseHandler onSuccess f = do
r <- f
case r of
Left e -> throw err500 {errBody = TLE.encodeUtf8 $ TL.fromStrict e}
Right s -> return $ onSuccess s
Note that A
-suffixed types are DTO
s, used to stabilize the API.
newtype AmountA = AmountA {cents :: Int}
deriving stock (Eq, Ord, Show, Generic)
deriving anyclass (FromJSON, ToJSON)
toAmount x = Entities.Amount x.cents