-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A family of combinators for defining webservices APIs and serving them -- -- A family of combinators for defining webservices APIs and serving them -- -- You can learn about the basics in the tutorial. -- -- Here is a runnable example, with comments, that defines a dummy -- API and implements a webserver that serves this API, using this -- package. -- -- CHANGELOG @package servant-server @version 0.9 module Servant.Server.Internal.Context -- | Contexts are used to pass values to combinators. (They are -- not meant to be used to pass parameters to your handlers, i.e. -- they should not replace any custom ReaderT-monad-stack that -- you're using with Enter.) If you don't use combinators that -- require any context entries, you can just use serve as always. -- -- If you are using combinators that require a non-empty Context -- you have to use serveWithContext and pass it a Context -- that contains all the values your combinators need. A Context -- is essentially a heterogenous list and accessing the elements is being -- done by type (see getContextEntry). The parameter of the type -- Context is a type-level list reflecting the types of the -- contained context entries. To create a Context with entries, -- use the operator (:.): -- --
-- >>> :type True :. () :. EmptyContext -- True :. () :. EmptyContext :: Context '[Bool, ()] --data Context contextTypes [EmptyContext] :: Context '[] [:.] :: x -> Context xs -> Context (x : xs) -- | This class is used to access context entries in Contexts. -- getContextEntry returns the first value where the type matches: -- --
-- >>> getContextEntry (True :. False :. EmptyContext) :: Bool -- True ---- -- If the Context does not contain an entry of the requested type, -- you'll get an error: -- --
-- >>> getContextEntry (True :. False :. EmptyContext) :: String -- ... -- ...No instance for (HasContextEntry '[] [Char]) -- ... --class HasContextEntry (context :: [*]) (val :: *) getContextEntry :: HasContextEntry context val => Context context -> val -- | Normally context entries are accessed by their types. In case you need -- to have multiple values of the same type in your Context and -- need to access them, we provide NamedContext. You can think of -- it as sub-namespaces for Contexts. data NamedContext (name :: Symbol) (subContext :: [*]) NamedContext :: (Context subContext) -> NamedContext -- | descendIntoNamedContext allows you to access -- NamedContexts. Usually you won't have to use it yourself but -- instead use a combinator like WithNamedContext. -- -- This is how descendIntoNamedContext works: -- --
-- >>> :set -XFlexibleContexts -- -- >>> let subContext = True :. EmptyContext -- -- >>> :type subContext -- subContext :: Context '[Bool] -- -- >>> let parentContext = False :. (NamedContext subContext :: NamedContext "subContext" '[Bool]) :. EmptyContext -- -- >>> :type parentContext -- parentContext :: Context '[Bool, NamedContext "subContext" '[Bool]] -- -- >>> descendIntoNamedContext (Proxy :: Proxy "subContext") parentContext :: Context '[Bool] -- True :. EmptyContext --descendIntoNamedContext :: forall context name subContext. HasContextEntry context (NamedContext name subContext) => Proxy (name :: Symbol) -> Context context -> Context subContext instance GHC.Show.Show (Servant.Server.Internal.Context.Context '[]) instance (GHC.Show.Show a, GHC.Show.Show (Servant.Server.Internal.Context.Context as)) => GHC.Show.Show (Servant.Server.Internal.Context.Context (a : as)) instance GHC.Classes.Eq (Servant.Server.Internal.Context.Context '[]) instance (GHC.Classes.Eq a, GHC.Classes.Eq (Servant.Server.Internal.Context.Context as)) => GHC.Classes.Eq (Servant.Server.Internal.Context.Context (a : as)) instance Servant.Server.Internal.Context.HasContextEntry xs val => Servant.Server.Internal.Context.HasContextEntry (notIt : xs) val instance Servant.Server.Internal.Context.HasContextEntry (val : xs) val module Servant.Server.Internal.ServantErr data ServantErr ServantErr :: Int -> String -> ByteString -> [Header] -> ServantErr [errHTTPCode] :: ServantErr -> Int [errReasonPhrase] :: ServantErr -> String [errBody] :: ServantErr -> ByteString [errHeaders] :: ServantErr -> [Header] type Handler = ExceptT ServantErr IO responseServantErr :: ServantErr -> Response -- | err300 Multiple Choices -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err300 { errBody = "I can't choose." }
--
err300 :: ServantErr
-- | err301 Moved Permanently
--
-- Example:
--
-- -- failingHandler :: Handler () -- failingHandler = throwError err301 --err301 :: ServantErr -- | err302 Found -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err302 --err302 :: ServantErr -- | err303 See Other -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err303 --err303 :: ServantErr -- | err304 Not Modified -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err304 --err304 :: ServantErr -- | err305 Use Proxy -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err305 --err305 :: ServantErr -- | err307 Temporary Redirect -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err307 --err307 :: ServantErr -- | err400 Bad Request -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err400 { errBody = "Your request makes no sense to me." }
--
err400 :: ServantErr
-- | err401 Unauthorized
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err401 { errBody = "Your credentials are invalid." }
--
err401 :: ServantErr
-- | err402 Payment Required
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err402 { errBody = "You have 0 credits. Please give me $$$." }
--
err402 :: ServantErr
-- | err403 Forbidden
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err403 { errBody = "Please login first." }
--
err403 :: ServantErr
-- | err404 Not Found
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err404 { errBody = "(╯°□°)╯︵ ┻━┻)." }
--
err404 :: ServantErr
-- | err405 Method Not Allowed
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err405 { errBody = "Your account privileges does not allow for this. Please pay $$$." }
--
err405 :: ServantErr
-- | err406 Not Acceptable
--
-- Example:
--
-- -- failingHandler :: Handler () -- failingHandler = throwError err406 --err406 :: ServantErr -- | err407 Proxy Authentication Required -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err407 --err407 :: ServantErr -- | err409 Conflict -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
--
err409 :: ServantErr
-- | err410 Gone
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
--
err410 :: ServantErr
-- | err411 Length Required
--
-- Example:
--
-- -- failingHandler :: Handler () -- failingHandler = throwError err411 --err411 :: ServantErr -- | err412 Precondition Failed -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
--
err412 :: ServantErr
-- | err413 Request Entity Too Large
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err413 { errBody = "Request exceeded 64k." }
--
err413 :: ServantErr
-- | err414 Request-URI Too Large
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err414 { errBody = "Maximum length is 64." }
--
err414 :: ServantErr
-- | err415 Unsupported Media Type
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err415 { errBody = "Supported media types: gif, png" }
--
err415 :: ServantErr
-- | err416 Request range not satisfiable
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err416 { errBody = "Valid range is [0, 424242]." }
--
err416 :: ServantErr
-- | err417 Expectation Failed
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err417 { errBody = "I found a quux in the request. This isn't going to work." }
--
err417 :: ServantErr
-- | err500 Internal Server Error
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err500 { errBody = "Exception in module A.B.C:55. Have a great day!" }
--
err500 :: ServantErr
-- | err501 Not Implemented
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
--
err501 :: ServantErr
-- | err502 Bad Gateway
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err502 { errBody = "Tried gateway foo, bar, and baz. None responded." }
--
err502 :: ServantErr
-- | err503 Service Unavailable
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err503 { errBody = "We're rewriting in PHP." }
--
err503 :: ServantErr
-- | err504 Gateway Time-out
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
--
err504 :: ServantErr
-- | err505 HTTP Version not supported
--
-- Example usage:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err505 { errBody = "I support HTTP/4.0 only." }
--
err505 :: ServantErr
instance GHC.Read.Read Servant.Server.Internal.ServantErr.ServantErr
instance GHC.Classes.Eq Servant.Server.Internal.ServantErr.ServantErr
instance GHC.Show.Show Servant.Server.Internal.ServantErr.ServantErr
instance GHC.Exception.Exception Servant.Server.Internal.ServantErr.ServantErr
module Servant.Server.Internal.RoutingApplication
type RoutingApplication = Request the request, the field 'pathInfo' may be modified by url routing -> (RouteResult Response -> IO ResponseReceived) -> IO ResponseReceived
-- | The result of matching against a path in the route tree.
data RouteResult a
-- | Keep trying other paths. The ServantErr should only be 404,
-- 405 or 406.
Fail :: ServantErr -> RouteResult a
-- | Don't try other paths.
FailFatal :: !ServantErr -> RouteResult a
Route :: !a -> RouteResult a
toApplication :: RoutingApplication -> Application
-- | A Delayed is a representation of a handler with scheduled
-- delayed checks that can trigger errors.
--
-- Why would we want to delay checks?
--
-- There are two reasons:
--
-- -- 404 -- 405 (bad method) -- 401 (unauthorized) -- 415 (unsupported media type) -- 400 (bad request) -- 406 (not acceptable) ---- -- Therefore, while routing, we delay most checks so that they will -- ultimately occur in the right order. -- -- A Delayed contains three delayed blocks of tests, and the -- actual handler: -- --
-- type MyApi = "books" :> Get '[JSON] [Book] -- GET /books -- :<|> "books" :> ReqBody Book :> Post '[JSON] Book -- POST /books -- -- server :: Server MyApi -- server = listAllBooks :<|> postBook -- where listAllBooks = ... -- postBook book = ... ---- | If you use Capture in one of the endpoints for your API, this -- automatically requires your server-side handler to be a function that -- takes an argument of the type specified by the Capture. This -- lets servant worry about getting it from the URL and turning it into a -- value of the type you specify. -- -- You can control how it'll be converted from Text to your type -- by simply providing an instance of FromHttpApiData for your -- type. -- -- Example: -- --
-- type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book -- -- server :: Server MyApi -- server = getBook -- where getBook :: Text -> Handler Book -- getBook isbn = ... ---- | If you use CaptureAll in one of the endpoints for your API, -- this automatically requires your server-side handler to be a function -- that takes an argument of a list of the type specified by the -- CaptureAll. This lets servant worry about getting values from -- the URL and turning them into values of the type you specify. -- -- You can control how they'll be converted from Text to your -- type by simply providing an instance of FromHttpApiData for -- your type. -- -- Example: -- --
-- type MyApi = "src" :> CaptureAll "segments" Text :> Get '[JSON] SourceFile -- -- server :: Server MyApi -- server = getSourceFile -- where getSourceFile :: [Text] -> Handler Book -- getSourceFile pathSegments = ... --allowedMethodHead :: Method -> Request -> Bool allowedMethod :: Method -> Request -> Bool processMethodRouter :: Maybe (ByteString, ByteString) -> Status -> Method -> Maybe [(HeaderName, ByteString)] -> Request -> RouteResult Response methodCheck :: Method -> Request -> DelayedIO () acceptCheck :: (AllMime list) => Proxy list -> ByteString -> DelayedIO () methodRouter :: (AllCTRender ctypes a) => Method -> Proxy ctypes -> Status -> Delayed env (Handler a) -> Router env methodRouterHeaders :: (GetHeaders (Headers h v), AllCTRender ctypes v) => Method -> Proxy ctypes -> Status -> Delayed env (Handler (Headers h v)) -> Router env -- | If you use Header in one of the endpoints for your API, this -- automatically requires your server-side handler to be a function that -- takes an argument of the type specified by Header. This lets -- servant worry about extracting it from the request and turning it into -- a value of the type you specify. -- -- All it asks is for a FromHttpApiData instance. -- -- Example: -- --
-- newtype Referer = Referer Text -- deriving (Eq, Show, FromHttpApiData) -- -- -- GET /view-my-referer -- type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer -- -- server :: Server MyApi -- server = viewReferer -- where viewReferer :: Referer -> Handler referer -- viewReferer referer = return referer ---- | If you use QueryParam "author" Text in one of the -- endpoints for your API, this automatically requires your server-side -- handler to be a function that takes an argument of type -- Maybe Text. -- -- This lets servant worry about looking it up in the query string and -- turning it into a value of the type you specify, enclosed in -- Maybe, because it may not be there and servant would then hand -- you Nothing. -- -- You can control how it'll be converted from Text to your type -- by simply providing an instance of FromHttpApiData for your -- type. -- -- Example: -- --
-- type MyApi = "books" :> QueryParam "author" Text :> Get '[JSON] [Book] -- -- server :: Server MyApi -- server = getBooksBy -- where getBooksBy :: Maybe Text -> Handler [Book] -- getBooksBy Nothing = ...return all books... -- getBooksBy (Just author) = ...return books by the given author... ---- | If you use QueryParams "authors" Text in one of the -- endpoints for your API, this automatically requires your server-side -- handler to be a function that takes an argument of type -- [Text]. -- -- This lets servant worry about looking up 0 or more values in the query -- string associated to authors and turning each of them into a -- value of the type you specify. -- -- You can control how the individual values are converted from -- Text to your type by simply providing an instance of -- FromHttpApiData for your type. -- -- Example: -- --
-- type MyApi = "books" :> QueryParams "authors" Text :> Get '[JSON] [Book] -- -- server :: Server MyApi -- server = getBooksBy -- where getBooksBy :: [Text] -> Handler [Book] -- getBooksBy authors = ...return all books by these authors... ---- | If you use QueryFlag "published" in one of the -- endpoints for your API, this automatically requires your server-side -- handler to be a function that takes an argument of type Bool. -- -- Example: -- --
-- type MyApi = "books" :> QueryFlag "published" :> Get '[JSON] [Book] -- -- server :: Server MyApi -- server = getBooks -- where getBooks :: Bool -> Handler [Book] -- getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument... ---- | Just pass the request to the underlying application and serve its -- response. -- -- Example: -- --
-- type MyApi = "images" :> Raw -- -- server :: Server MyApi -- server = serveDirectory "/var/www/images" ---- | If you use ReqBody in one of the endpoints for your API, this -- automatically requires your server-side handler to be a function that -- takes an argument of the type specified by ReqBody. The -- Content-Type header is inspected, and the list provided is -- used to attempt deserialization. If the request does not have a -- Content-Type header, it is treated as -- application/octet-stream (as specified in RFC7231. -- This lets servant worry about extracting it from the request and -- turning it into a value of the type you specify. -- -- All it asks is for a FromJSON instance. -- -- Example: -- --
-- type MyApi = "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book -- -- server :: Server MyApi -- server = postBook -- where postBook :: Book -> Handler Book -- postBook book = ...insert into your db... ---- | Make sure the incoming request starts with "/path", strip it -- and pass the rest of the request path to api. -- | Basic Authentication ct_wildcard :: ByteString instance (Servant.Server.Internal.HasServer a context, Servant.Server.Internal.HasServer b context) => Servant.Server.Internal.HasServer (a Servant.API.Alternative.:<|> b) context instance forall k1 (capture :: GHC.Types.Symbol) a (api :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol capture, Web.Internal.HttpApiData.FromHttpApiData a, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (Servant.API.Capture.Capture capture a Servant.API.Sub.:> api) context instance forall k1 (capture :: GHC.Types.Symbol) a (sublayout :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol capture, Web.Internal.HttpApiData.FromHttpApiData a, Servant.Server.Internal.HasServer sublayout context) => Servant.Server.Internal.HasServer (Servant.API.Capture.CaptureAll capture a Servant.API.Sub.:> sublayout) context instance forall k1 (ctypes :: [GHC.Types.*]) a (method :: k1) (status :: GHC.Types.Nat) (context :: [*]). (Servant.API.ContentTypes.AllCTRender ctypes a, Servant.API.Verbs.ReflectMethod method, GHC.TypeLits.KnownNat status) => Servant.Server.Internal.HasServer (Servant.API.Verbs.Verb method status ctypes a) context instance forall k1 (ctypes :: [GHC.Types.*]) a (method :: k1) (status :: GHC.Types.Nat) (h :: [*]) (context :: [*]). (Servant.API.ContentTypes.AllCTRender ctypes a, Servant.API.Verbs.ReflectMethod method, GHC.TypeLits.KnownNat status, Servant.API.ResponseHeaders.GetHeaders (Servant.API.ResponseHeaders.Headers h a)) => Servant.Server.Internal.HasServer (Servant.API.Verbs.Verb method status ctypes (Servant.API.ResponseHeaders.Headers h a)) context instance forall k1 (sym :: GHC.Types.Symbol) a (api :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol sym, Web.Internal.HttpApiData.FromHttpApiData a, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (Servant.API.Header.Header sym a Servant.API.Sub.:> api) context instance forall k1 (sym :: GHC.Types.Symbol) a (api :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol sym, Web.Internal.HttpApiData.FromHttpApiData a, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (Servant.API.QueryParam.QueryParam sym a Servant.API.Sub.:> api) context instance forall k1 (sym :: GHC.Types.Symbol) a (api :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol sym, Web.Internal.HttpApiData.FromHttpApiData a, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (Servant.API.QueryParam.QueryParams sym a Servant.API.Sub.:> api) context instance forall k1 (sym :: GHC.Types.Symbol) (api :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol sym, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (Servant.API.QueryParam.QueryFlag sym Servant.API.Sub.:> api) context instance Servant.Server.Internal.HasServer Servant.API.Raw.Raw context instance forall k1 (list :: [GHC.Types.*]) a (api :: k1) (context :: [*]). (Servant.API.ContentTypes.AllCTUnrender list a, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (Servant.API.ReqBody.ReqBody list a Servant.API.Sub.:> api) context instance forall k1 (path :: GHC.Types.Symbol) (api :: k1) (context :: [*]). (GHC.TypeLits.KnownSymbol path, Servant.Server.Internal.HasServer api context) => Servant.Server.Internal.HasServer (path Servant.API.Sub.:> api) context instance forall k1 (api :: k1) (context :: [*]). Servant.Server.Internal.HasServer api context => Servant.Server.Internal.HasServer (Servant.API.RemoteHost.RemoteHost Servant.API.Sub.:> api) context instance forall k1 (api :: k1) (context :: [*]). Servant.Server.Internal.HasServer api context => Servant.Server.Internal.HasServer (Servant.API.IsSecure.IsSecure Servant.API.Sub.:> api) context instance forall k1 (api :: k1) (context :: [*]). Servant.Server.Internal.HasServer api context => Servant.Server.Internal.HasServer (Data.Vault.Lazy.Vault Servant.API.Sub.:> api) context instance forall k1 (api :: k1) (context :: [*]). Servant.Server.Internal.HasServer api context => Servant.Server.Internal.HasServer (Network.HTTP.Types.Version.HttpVersion Servant.API.Sub.:> api) context instance forall k1 (realm :: GHC.Types.Symbol) (api :: k1) (context :: [*]) usr. (GHC.TypeLits.KnownSymbol realm, Servant.Server.Internal.HasServer api context, Servant.Server.Internal.Context.HasContextEntry context (Servant.Server.Internal.BasicAuth.BasicAuthCheck usr)) => Servant.Server.Internal.HasServer (Servant.API.BasicAuth.BasicAuth realm usr Servant.API.Sub.:> api) context instance (Servant.Server.Internal.Context.HasContextEntry context (Servant.Server.Internal.Context.NamedContext name subContext), Servant.Server.Internal.HasServer subApi subContext) => Servant.Server.Internal.HasServer (Servant.API.WithNamedContext.WithNamedContext name subContext subApi) context -- | This module lets you implement Servers for defined APIs. You'll -- most likely just need serve. module Servant.Server -- | serve allows you to implement an API and produce a wai -- Application. -- -- Example: -- --
-- type MyApi = "books" :> Get '[JSON] [Book] -- GET /books -- :<|> "books" :> ReqBody Book :> Post '[JSON] Book -- POST /books -- -- server :: Server MyApi -- server = listAllBooks :<|> postBook -- where listAllBooks = ... -- postBook book = ... -- -- myApi :: Proxy MyApi -- myApi = Proxy -- -- app :: Application -- app = serve myApi server -- -- main :: IO () -- main = Network.Wai.Handler.Warp.run 8080 app --serve :: (HasServer api '[]) => Proxy api -> Server api -> Application serveWithContext :: (HasServer api context) => Proxy api -> Context context -> Server api -> Application toApplication :: RoutingApplication -> Application class HasServer api context where type ServerT api (m :: * -> *) :: * where { type family ServerT api (m :: * -> *) :: *; } route :: HasServer api context => Proxy api -> Context context -> Delayed env (Server api) -> Router env type Server api = ServerT api Handler type Handler = ExceptT ServantErr IO -- | The function layout produces a textual description of the -- internal router layout for debugging purposes. Note that the router -- layout is determined just by the API, not by the handlers. -- -- Example: -- -- For the following API -- --
-- type API = -- "a" :> "d" :> Get '[JSON] NoContent -- :<|> "b" :> Capture "x" Int :> Get '[JSON] Bool -- :<|> "c" :> Put '[JSON] Bool -- :<|> "a" :> "e" :> Get '[JSON] Int -- :<|> "b" :> Capture "x" Int :> Put '[JSON] Bool -- :<|> Raw ---- -- we get the following output: -- --
-- / -- ├─ a/ -- │ ├─ d/ -- │ │ └─• -- │ └─ e/ -- │ └─• -- ├─ b/ -- │ └─ <capture>/ -- │ ├─• -- │ ┆ -- │ └─• -- ├─ c/ -- │ └─• -- ┆ -- └─ <raw> ---- -- Explanation of symbols: -- --
-- >>> :type True :. () :. EmptyContext -- True :. () :. EmptyContext :: Context '[Bool, ()] --data Context contextTypes [EmptyContext] :: Context '[] [:.] :: x -> Context xs -> Context (x : xs) -- | This class is used to access context entries in Contexts. -- getContextEntry returns the first value where the type matches: -- --
-- >>> getContextEntry (True :. False :. EmptyContext) :: Bool -- True ---- -- If the Context does not contain an entry of the requested type, -- you'll get an error: -- --
-- >>> getContextEntry (True :. False :. EmptyContext) :: String -- ... -- ...No instance for (HasContextEntry '[] [Char]) -- ... --class HasContextEntry (context :: [*]) (val :: *) getContextEntry :: HasContextEntry context val => Context context -> val -- | Normally context entries are accessed by their types. In case you need -- to have multiple values of the same type in your Context and -- need to access them, we provide NamedContext. You can think of -- it as sub-namespaces for Contexts. data NamedContext (name :: Symbol) (subContext :: [*]) NamedContext :: (Context subContext) -> NamedContext -- | descendIntoNamedContext allows you to access -- NamedContexts. Usually you won't have to use it yourself but -- instead use a combinator like WithNamedContext. -- -- This is how descendIntoNamedContext works: -- --
-- >>> :set -XFlexibleContexts -- -- >>> let subContext = True :. EmptyContext -- -- >>> :type subContext -- subContext :: Context '[Bool] -- -- >>> let parentContext = False :. (NamedContext subContext :: NamedContext "subContext" '[Bool]) :. EmptyContext -- -- >>> :type parentContext -- parentContext :: Context '[Bool, NamedContext "subContext" '[Bool]] -- -- >>> descendIntoNamedContext (Proxy :: Proxy "subContext") parentContext :: Context '[Bool] -- True :. EmptyContext --descendIntoNamedContext :: forall context name subContext. HasContextEntry context (NamedContext name subContext) => Proxy (name :: Symbol) -> Context context -> Context subContext -- | Datatype wrapping a function used to check authentication. newtype BasicAuthCheck usr BasicAuthCheck :: (BasicAuthData -> IO (BasicAuthResult usr)) -> BasicAuthCheck usr [unBasicAuthCheck] :: BasicAuthCheck usr -> BasicAuthData -> IO (BasicAuthResult usr) -- | servant-server's current implementation of basic authentication is not -- immune to certian kinds of timing attacks. Decoding payloads does not -- take a fixed amount of time. -- -- The result of authentication/authorization data BasicAuthResult usr Unauthorized :: BasicAuthResult usr BadPassword :: BasicAuthResult usr NoSuchUser :: BasicAuthResult usr Authorized :: usr -> BasicAuthResult usr data ServantErr ServantErr :: Int -> String -> ByteString -> [Header] -> ServantErr [errHTTPCode] :: ServantErr -> Int [errReasonPhrase] :: ServantErr -> String [errBody] :: ServantErr -> ByteString [errHeaders] :: ServantErr -> [Header] -- | err300 Multiple Choices -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err300 { errBody = "I can't choose." }
--
err300 :: ServantErr
-- | err301 Moved Permanently
--
-- Example:
--
-- -- failingHandler :: Handler () -- failingHandler = throwError err301 --err301 :: ServantErr -- | err302 Found -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err302 --err302 :: ServantErr -- | err303 See Other -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err303 --err303 :: ServantErr -- | err304 Not Modified -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err304 --err304 :: ServantErr -- | err305 Use Proxy -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err305 --err305 :: ServantErr -- | err307 Temporary Redirect -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err307 --err307 :: ServantErr -- | err400 Bad Request -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err400 { errBody = "Your request makes no sense to me." }
--
err400 :: ServantErr
-- | err401 Unauthorized
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err401 { errBody = "Your credentials are invalid." }
--
err401 :: ServantErr
-- | err402 Payment Required
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err402 { errBody = "You have 0 credits. Please give me $$$." }
--
err402 :: ServantErr
-- | err403 Forbidden
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err403 { errBody = "Please login first." }
--
err403 :: ServantErr
-- | err404 Not Found
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err404 { errBody = "(╯°□°)╯︵ ┻━┻)." }
--
err404 :: ServantErr
-- | err405 Method Not Allowed
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err405 { errBody = "Your account privileges does not allow for this. Please pay $$$." }
--
err405 :: ServantErr
-- | err406 Not Acceptable
--
-- Example:
--
-- -- failingHandler :: Handler () -- failingHandler = throwError err406 --err406 :: ServantErr -- | err407 Proxy Authentication Required -- -- Example: -- --
-- failingHandler :: Handler () -- failingHandler = throwError err407 --err407 :: ServantErr -- | err409 Conflict -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
--
err409 :: ServantErr
-- | err410 Gone
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
--
err410 :: ServantErr
-- | err411 Length Required
--
-- Example:
--
-- -- failingHandler :: Handler () -- failingHandler = throwError err411 --err411 :: ServantErr -- | err412 Precondition Failed -- -- Example: -- --
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
--
err412 :: ServantErr
-- | err413 Request Entity Too Large
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err413 { errBody = "Request exceeded 64k." }
--
err413 :: ServantErr
-- | err414 Request-URI Too Large
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err414 { errBody = "Maximum length is 64." }
--
err414 :: ServantErr
-- | err415 Unsupported Media Type
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err415 { errBody = "Supported media types: gif, png" }
--
err415 :: ServantErr
-- | err416 Request range not satisfiable
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err416 { errBody = "Valid range is [0, 424242]." }
--
err416 :: ServantErr
-- | err417 Expectation Failed
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err417 { errBody = "I found a quux in the request. This isn't going to work." }
--
err417 :: ServantErr
-- | err500 Internal Server Error
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err500 { errBody = "Exception in module A.B.C:55. Have a great day!" }
--
err500 :: ServantErr
-- | err501 Not Implemented
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
--
err501 :: ServantErr
-- | err502 Bad Gateway
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err502 { errBody = "Tried gateway foo, bar, and baz. None responded." }
--
err502 :: ServantErr
-- | err503 Service Unavailable
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err503 { errBody = "We're rewriting in PHP." }
--
err503 :: ServantErr
-- | err504 Gateway Time-out
--
-- Example:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
--
err504 :: ServantErr
-- | err505 HTTP Version not supported
--
-- Example usage:
--
--
-- failingHandler :: Handler ()
-- failingHandler = throwError $ err505 { errBody = "I support HTTP/4.0 only." }
--
err505 :: ServantErr
-- | The WAI application.
--
-- Note that, since WAI 3.0, this type is structured in continuation
-- passing style to allow for proper safe resource handling. This was
-- handled in the past via other means (e.g., ResourceT). As a
-- demonstration:
--
-- -- app :: Application -- app req respond = bracket_ -- (putStrLn "Allocating scarce resource") -- (putStrLn "Cleaning up") -- (respond $ responseLBS status200 [] "Hello World") --type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived -- | This module defines a sever-side handler that lets you serve static -- files. -- --
-- type MyApi = "static" :> Raw -- -- server :: Server MyApi -- server = serveDirectory "/var/www" ---- -- would capture any request to /static/<something> and -- look for <something> under /var/www. -- -- It will do its best to guess the MIME type for that file, based on the -- extension, and send an appropriate Content-Type header if -- possible. -- -- If your goal is to serve HTML, CSS and Javascript files that use the -- rest of the API as a webapp backend, you will most likely not want the -- static files to be hidden behind a /static/ prefix. In that -- case, remember to put the serveDirectory handler in the last -- position, because servant will try to match the handlers in -- order. serveDirectory :: FilePath -> Server Raw module Servant -- | A concrete, poly-kinded proxy type data Proxy k (t :: k) :: forall k. k -> * Proxy :: Proxy k -- | Is used within a monadic computation to begin exception processing. throwError :: MonadError e m => forall a. e -> m a module Servant.Server.Experimental.Auth -- | Specify the type of data returned after we've authenticated a request. -- quite often this is some User datatype. -- -- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE -- | Handlers for AuthProtected resources -- -- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE newtype AuthHandler r usr AuthHandler :: (r -> Handler usr) -> AuthHandler r usr [unAuthHandler] :: AuthHandler r usr -> r -> Handler usr -- | NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE mkAuthHandler :: (r -> Handler usr) -> AuthHandler r usr -- | Known orphan instance. instance GHC.Generics.Generic (Servant.Server.Experimental.Auth.AuthHandler r usr) instance forall k1 k (api :: k1) (context :: [*]) (tag :: k). (Servant.Server.Internal.HasServer api context, Servant.Server.Internal.Context.HasContextEntry context (Servant.Server.Experimental.Auth.AuthHandler Network.Wai.Internal.Request (Servant.Server.Experimental.Auth.AuthServerData (Servant.API.Experimental.Auth.AuthProtect tag)))) => Servant.Server.Internal.HasServer (Servant.API.Experimental.Auth.AuthProtect tag Servant.API.Sub.:> api) context