content: {-# 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.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
  