on 1dd253d help sign in
68 lines 2.6 kB history raw
1{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE DeriveDataTypeable #-}
5module Servant.API.Get where
7import Control.Monad.Trans.Either
8import Data.Aeson
9import Data.Proxy
10import Data.String.Conversions
11import Data.Typeable
12import Network.HTTP.Types
13import Network.Wai
14import Servant.Client
15import Servant.Common.BaseUrl
16import Servant.Common.Req
17import Servant.Docs
18import Servant.Server
20-- | Endpoint for simple GET requests. Serves the result as JSON.
21--
22-- Example:
23--
24-- > type MyApi = "books" :> Get [Book]
25data Get a
26 deriving Typeable
28-- | When implementing the handler for a 'Get' endpoint,
29-- just like for 'Servant.API.Delete.Delete', 'Servant.API.Post.Post'
30-- and 'Servant.API.Put.Put', the handler code runs in the
31-- @EitherT (Int, String) IO@ monad, where the 'Int' represents
32-- the status code and the 'String' a message, returned in case of
33-- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left'
34-- to quickly fail if some conditions are not met.
35--
36-- If successfully returning a value, we just require that its type has
37-- a 'ToJSON' instance and servant takes care of encoding it for you,
38-- yielding status code 200 along the way.
39instance ToJSON result => HasServer (Get result) where
40 type Server (Get result) = EitherT (Int, String) IO result
41 route Proxy action request respond
42 | null (pathInfo request) && requestMethod request == methodGet = do
43 e <- runEitherT action
44 respond . succeedWith $ case e of
45 Right output ->
46 responseLBS ok200 [("Content-Type", "application/json")] (encode output)
47 Left (status, message) ->
48 responseLBS (mkStatus status (cs message)) [] (cs message)
49 | null (pathInfo request) && requestMethod request /= methodGet =
50 respond $ failWith WrongMethod
51 | otherwise = respond $ failWith NotFound
53-- | If you have a 'Get' endpoint in your API, the client
54-- side querying function that is created when calling 'client'
55-- will just require an argument that specifies the scheme, host
56-- and port to send the request to.
57instance FromJSON result => HasClient (Get result) where
58 type Client (Get result) = BaseUrl -> EitherT String IO result
59 clientWithRoute Proxy req host =
60 performRequestJSON methodGet req 200 host
62instance ToSample a => HasDocs (Get a) where
63 docsFor Proxy (endpoint, action) =
64 single endpoint' action'
66 where endpoint' = endpoint & method .~ DocGET
67 action' = action & response.respBody .~ sampleByteString p
68 p = Proxy :: Proxy a