on master help sign in
removing Generic cookbook in favour of NamedRoutes
commit34aed1d28989a8a91ddc64e7aafafdc807d71249 authorakhesaCaro <caroline.gaudreau@gmail.com> dateThu 17 Feb 2022, 16:11 (5 years ago) parent5c80214
3 files changed−167
cabal.project−1 doc/cookbook/generic/Generic.lhs−141 doc/cookbook/generic/generic.cabal−25
cabal.project−1
@@ -34,7 +34,6 @@ packages:
3434 doc/cookbook/db-postgres-pool
3535 doc/cookbook/db-sqlite-simple
3636 doc/cookbook/file-upload
37− doc/cookbook/generic
3837 doc/cookbook/hoist-server-with-context
3938 doc/cookbook/https
4039 doc/cookbook/jwt-and-basic-auth
doc/cookbook/generic/Generic.lhsdeleted−141
@@ -1,141 +0,0 @@
1−# Using generics
2−
3−```haskell
4−{-# LANGUAGE DataKinds #-}
5−{-# LANGUAGE DeriveGeneric #-}
6−{-# LANGUAGE RankNTypes #-}
7−{-# LANGUAGE TypeOperators #-}
8−module Main (main, api, getLink, routesLinks, cliGet) where
9−
10−import Control.Exception (throwIO)
11−import Control.Monad.Trans.Reader (ReaderT, runReaderT)
12−import Data.Proxy (Proxy (..))
13−import Network.Wai.Handler.Warp (run)
14−import System.Environment (getArgs)
15−
16−import Servant
17−import Servant.Client
18−
19−import Servant.API.Generic
20−import Servant.Client.Generic
21−import Servant.Server.Generic
22−```
23−
24−The usage is simple, if you only need a collection of routes.
25−First you define a record with field types prefixed by a parameter `route`:
26−
27−```haskell
28−data Routes route = Routes
29− { _get :: route :- Capture "id" Int :> Get '[JSON] String
30− , _put :: route :- ReqBody '[JSON] Int :> Put '[JSON] Bool
31− }
32− deriving (Generic)
33−```
34−
35−Then we'll use this data type to define API, links, server and client.
36−
37−## API
38−
39−You can get a `Proxy` of the API using `genericApi`:
40−
41−```haskell
42−api :: Proxy (ToServantApi Routes)
43−api = genericApi (Proxy :: Proxy Routes)
44−```
45−
46−It's recommended to use `genericApi` function, as then you'll get
47−better error message, for example if you forget to `derive Generic`.
48−
49−## Links
50−
51−The clear advantage of record-based generics approach, is that
52−we can get safe links very conveniently. We don't need to define endpoint types,
53−as field accessors work as proxies:
54−
55−```haskell
56−getLink :: Int -> Link
57−getLink = fieldLink _get
58−```
59−
60−We can also get all links at once, as a record:
61−
62−```haskell
63−routesLinks :: Routes (AsLink Link)
64−routesLinks = allFieldLinks
65−```
66−
67−## Client
68−
69−Even more power starts to show when we generate a record of client functions.
70−Here we use `genericClientHoist` function, which lets us simultaneously
71−hoist the monad, in this case from `ClientM` to `IO`.
72−
73−```haskell
74−cliRoutes :: Routes (AsClientT IO)
75−cliRoutes = genericClientHoist
76− (\x -> runClientM x env >>= either throwIO return)
77− where
78− env = error "undefined environment"
79−
80−cliGet :: Int -> IO String
81−cliGet = _get cliRoutes
82−```
83−
84−## Server
85−
86−Finally, probably the most handy usage: we can convert record of handlers into
87−the server implementation:
88−
89−```haskell
90−record :: Routes AsServer
91−record = Routes
92− { _get = return . show
93− , _put = return . odd
94− }
95−
96−app :: Application
97−app = genericServe record
98−
99−main :: IO ()
100−main = do
101− args <- getArgs
102− case args of
103− ("run":_) -> do
104− putStrLn "Starting cookbook-generic at http://localhost:8000"
105− run 8000 app
106− -- see this cookbook below for custom-monad explanation
107− ("run-custom-monad":_) -> do
108− putStrLn "Starting cookbook-generic with a custom monad at http://localhost:8000"
109− run 8000 (appMyMonad AppCustomState)
110− _ -> putStrLn "To run, pass 'run' argument: cabal new-run cookbook-generic run"
111−```
112−
113−## Using generics together with a custom monad
114−
115−If your app uses a custom monad, here's how you can combine it with
116−generics.
117−
118−```haskell
119−data AppCustomState =
120− AppCustomState
121−
122−type AppM = ReaderT AppCustomState Handler
123−
124−apiMyMonad :: Proxy (ToServantApi Routes)
125−apiMyMonad = genericApi (Proxy :: Proxy Routes)
126−
127−getRouteMyMonad :: Int -> AppM String
128−getRouteMyMonad = return . show
129−
130−putRouteMyMonad :: Int -> AppM Bool
131−putRouteMyMonad = return . odd
132−
133−recordMyMonad :: Routes (AsServerT AppM)
134−recordMyMonad = Routes {_get = getRouteMyMonad, _put = putRouteMyMonad}
135−
136−-- natural transformation
137−nt :: AppCustomState -> AppM a -> Handler a
138−nt s x = runReaderT x s
139−
140−appMyMonad :: AppCustomState -> Application
141−appMyMonad state = genericServeT (nt state) recordMyMonad
doc/cookbook/generic/generic.cabaldeleted−25
@@ -1,25 +0,0 @@
1−cabal-version: 2.2
2−name: cookbook-generic
3−version: 0.1
4−synopsis: Using custom monad to pass a state between handlers
5−homepage: http://docs.servant.dev/
6−license: BSD-3-Clause
7−license-file: ../../../servant/LICENSE
8−author: Servant Contributors
9−maintainer: haskell-servant-maintainers@googlegroups.com
10−build-type: Simple
11−tested-with: GHC==8.6.5, GHC==8.8.3, GHC ==8.10.7
12−
13−executable cookbook-using-custom-monad
14− main-is: Generic.lhs
15− build-depends: base == 4.*
16− , servant
17− , servant-client
18− , servant-client-core
19− , servant-server
20− , base-compat
21− , warp >= 3.2
22− , transformers >= 0.3
23− default-language: Haskell2010
24− ghc-options: -Wall -pgmL markdown-unlit
25− build-tool-depends: markdown-unlit:markdown-unlit >= 0.4