Adding paragraph to generic cookbook
This commit is contained in:
parent
ddfbac9dfc
commit
53f722d41c
1 changed files with 73 additions and 0 deletions
|
@ -10,6 +10,79 @@ case](../namedRoutes/NamedRoutes.html) cookbook that broaches the subject.
|
||||||
|
|
||||||
Shall we begin?
|
Shall we begin?
|
||||||
|
|
||||||
|
## Why would I want to use `Records` over the alternative `:<|>` operator?
|
||||||
|
|
||||||
|
With a record-based API, we don’t need to care about the declaration order of the endpoints.
|
||||||
|
For example, with the `:<|>` operator there’s room for error when the order of the API type
|
||||||
|
|
||||||
|
```haskell,ignore
|
||||||
|
type API1 = "version" :> Get '[JSON] Version
|
||||||
|
:<|> "movies" :> Get '[JSON] [Movie]
|
||||||
|
```
|
||||||
|
does not follow the `Handler` implementation order
|
||||||
|
```haskell,ignore
|
||||||
|
apiHandler :: ServerT API1 Handler
|
||||||
|
apiHandler = getMovies
|
||||||
|
:<|> getVersion
|
||||||
|
```
|
||||||
|
GHC could scold you with a very tedious message such as :
|
||||||
|
```console
|
||||||
|
• Couldn't match type 'Handler NoContent'
|
||||||
|
with 'Movie -> Handler NoContent'
|
||||||
|
Expected type: ServerT MovieCatalogAPI Handler
|
||||||
|
Actual type: Handler Version
|
||||||
|
:<|> ((Maybe SortBy -> Handler [Movie])
|
||||||
|
:<|> ((MovieId -> Handler (Maybe Movie))
|
||||||
|
:<|> ((MovieId -> Movie -> Handler NoContent)
|
||||||
|
:<|> (MovieId -> Handler NoContent))))
|
||||||
|
• In the expression:
|
||||||
|
versionHandler
|
||||||
|
:<|>
|
||||||
|
movieListHandler
|
||||||
|
:<|>
|
||||||
|
getMovieHandler :<|> updateMovieHandler :<|> deleteMovieHandler
|
||||||
|
In an equation for 'server':
|
||||||
|
server
|
||||||
|
= versionHandler
|
||||||
|
:<|>
|
||||||
|
movieListHandler
|
||||||
|
:<|>
|
||||||
|
getMovieHandler :<|> updateMovieHandler :<|> deleteMovieHandler
|
||||||
|
|
|
||||||
|
226 | server = versionHandler
|
||||||
|
```
|
||||||
|
On the contrary, with the record-based technique, we refer to the routes by their name:
|
||||||
|
```haskell,ignore
|
||||||
|
data API mode = API
|
||||||
|
{ list :: "list" :> ...
|
||||||
|
, delete :: "delete" :> ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
and GHC follows the lead :
|
||||||
|
```console
|
||||||
|
• Couldn't match type 'NoContent' with 'Movie'
|
||||||
|
Expected type: AsServerT Handler :- Delete '[JSON] Movie
|
||||||
|
Actual type: Handler NoContent
|
||||||
|
• In the 'delete' field of a record
|
||||||
|
In the expression:
|
||||||
|
MovieAPI
|
||||||
|
{get = getMovieHandler movieId,
|
||||||
|
update = updateMovieHandler movieId,
|
||||||
|
delete = deleteMovieHandler movieId}
|
||||||
|
In an equation for 'movieHandler':
|
||||||
|
movieHandler movieId
|
||||||
|
= MovieAPI
|
||||||
|
{get = getMovieHandler movieId,
|
||||||
|
update = updateMovieHandler movieId,
|
||||||
|
delete = deleteMovieHandler movieId}
|
||||||
|
|
|
||||||
|
252 | , delete = deleteMovieHandler movieId
|
||||||
|
```
|
||||||
|
|
||||||
|
So, records are more readable for a human, and GHC gives you more accurate error messages.
|
||||||
|
|
||||||
|
What are we waiting for?
|
||||||
|
|
||||||
```haskell
|
```haskell
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
|
Loading…
Reference in a new issue