{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE DeriveDataTypeable #-} module Servant.API.Get where import Control.Monad.Trans.Either import Data.Aeson import Data.Proxy import Data.String.Conversions import Data.Typeable import Network.HTTP.Types import Network.Wai import Servant.Client import Servant.Common.BaseUrl import Servant.Common.Req import Servant.Docs import Servant.Server -- | Endpoint for simple GET requests. Serves the result as JSON. -- -- Example: -- -- > type MyApi = "books" :> Get [Book] data Get a deriving Typeable -- | When implementing the handler for a 'Get' endpoint, -- just like for 'Servant.API.Delete.Delete', 'Servant.API.Post.Post' -- and 'Servant.API.Put.Put', the handler code runs in the -- @EitherT (Int, String) IO@ monad, where the 'Int' represents -- the status code and the 'String' a message, returned in case of -- failure. You can quite handily use 'Control.Monad.Trans.EitherT.left' -- to quickly fail if some conditions are not met. -- -- If successfully returning a value, we just require that its type has -- a 'ToJSON' instance and servant takes care of encoding it for you, -- yielding status code 200 along the way. instance ToJSON result => HasServer (Get result) where type Server (Get result) = EitherT (Int, String) IO result route Proxy action request respond | null (pathInfo request) && requestMethod request == methodGet = do e <- runEitherT action respond . succeedWith $ case e of Right output -> responseLBS ok200 [("Content-Type", "application/json")] (encode output) Left (status, message) -> responseLBS (mkStatus status (cs message)) [] (cs message) | null (pathInfo request) && requestMethod request /= methodGet = respond $ failWith WrongMethod | otherwise = respond $ failWith NotFound -- | If you have a 'Get' endpoint in your API, the client -- side querying function that is created when calling 'client' -- will just require an argument that specifies the scheme, host -- and port to send the request to. instance FromJSON result => HasClient (Get result) where type Client (Get result) = BaseUrl -> EitherT String IO result clientWithRoute Proxy req host = performRequestJSON methodGet req 200 host instance ToSample a => HasDocs (Get a) where docsFor Proxy (endpoint, action) = single endpoint' action' where endpoint' = endpoint & method .~ DocGET action' = action & response.respBody .~ sampleByteString p p = Proxy :: Proxy a