diff --git a/doc/cookbook/generic/Generic.lhs b/doc/cookbook/generic/Generic.lhs index 24463c20..4ea1c747 100644 --- a/doc/cookbook/generic/Generic.lhs +++ b/doc/cookbook/generic/Generic.lhs @@ -10,6 +10,79 @@ case](../namedRoutes/NamedRoutes.html) cookbook that broaches the subject. 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 {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-}