HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Run a wai application from an API

4 declarations
valueserve :: HasServer api '[] => Proxy api -> Server api -> Application
#

serve allows you to implement an API and produce a wai Application.

Example:

type MyApi = "books" :> Get '[JSON] [Book] -- GET /books
        :<|> "books" :> ReqBody '[JSON] 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

Construct a wai Application from an API

1 declaration

Handlers for all standard combinators

7 declarations
classclass HasServer (api :: k) (context :: [Type]) where
#

Associated types

  • type family ServerT (api :: k) (m :: Type -> Type)

    The type of a server for this API, given a monad to run effects in.

    Note that the result kind is *, so it is not a monad transformer, unlike what the T in the name might suggest.

Methods

Instances38HasServer, …
  • TypeError (NoInstanceFor (HasServer api context)) => HasServer api contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • HasServer EmptyAPI contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    The server for an EmptyAPI is emptyServer.

    type MyApi = "nothing" :> EmptyApi
    
    server :: Server MyApi
    server = emptyServer
  • HasServer Raw contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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"
  • HasServer RawM contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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"
  • (HasServer (ToServantApi api) context, forall (m :: Type -> Type). Generic (api (AsServerT m)), forall (m :: Type -> Type). GServer api m, ErrorIfNoGeneric api) => HasServer (NamedRoutes api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • TypeError (HasServerArrowTypeError a b) => HasServer (a -> b) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    This instance prevents from accidentally using -> instead of :>

    Example1 expression
    serve (Proxy :: Proxy (Capture "foo" Int -> Get '[JSON] Int)) (error "...")......No instance HasServer (a -> b)....Maybe you have used '->' instead of ':>' between...Capture' '[] "foo" Int...and...Verb 'GET 200 '[JSON] Int...
    Example1 expression
    undefined :: Server (Capture "foo" Int -> Get '[JSON] Int)......No instance HasServer (a -> b)....Maybe you have used '->' instead of ':>' between...Capture' '[] "foo" Int...and...Verb 'GET 200 '[JSON] Int...
  • ReflectMethod method => HasServer (NoContentVerb method) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • (HasServer a context, HasServer b context) => HasServer (a :<|> b) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    A server for a :<|> b first tries to match the request against the route represented by a and if it fails tries b. You must provide a request handler for each route.

    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 = ...
  • TypeError (NoInstanceForSub HasServer ty) => HasServer (ty :> sub) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • TypeError (PartialApplication HasServer arr) => HasServer (arr :> sub) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • HasServer api context => HasServer (HttpVersion :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • HasServer api context => HasServer (EmptyAPI :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    Ignore EmptyAPI as part of route in server handlers.

  • HasServer api context => HasServer (IsSecure :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • HasServer api context => HasServer (QueryString :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    If you use QueryString 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 Query ([(ByteString, Maybe ByteString)]).

    This lets you extract the whole query string. This is useful when the query string can contain parameters with dynamic names, that you can't access with QueryParam.

    Example:

    type MyApi = "books" :> QueryString :> Get '[JSON] [Book]
    
    server :: Server MyApi
    server = getBooksBy
      where getBooksBy :: Query -> Handler [Book]
            getBooksBy filters = ...filter books based on the dynamic filters provided...
  • HasServer api context => HasServer (RemoteHost :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • HasServer api context => HasServer (Vault :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • HasServer api ctx => HasServer (Description desc :> api) ctxDefined in servant-server-0.20.2 · Servant.Server.Internal

    Ignore Description in server handlers.

  • HasServer api ctx => HasServer (Summary desc :> api) ctxDefined in servant-server-0.20.2 · Servant.Server.Internal

    Ignore Summary in server handlers.

  • (KnownSymbol capture, FromHttpApiData a, Typeable a, HasServer api context, HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (CaptureAll capture a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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 = ...
  • (KnownSymbol capture, FromHttpApiData a, Typeable a, HasServer api context, SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (Capture' mods capture a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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 = ...
  • (KnownSymbol path, HasServer api context) => HasServer (path :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    Make sure the incoming request starts with "/path", strip it and pass the rest of the request path to api.

  • (KnownSymbol realm, HasServer api context, HasContextEntry context (BasicAuthCheck usr)) => HasServer (BasicAuth realm usr :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    Basic Authentication

  • (KnownSymbol sym, FromHttpApiData a, HasServer api context, HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (QueryParams sym a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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...
  • (KnownSymbol sym, FromHttpApiData a, HasServer api context, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (Header' mods sym a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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
  • (KnownSymbol sym, FromHttpApiData a, HasServer api context, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (QueryParam' mods sym a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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...
  • (KnownSymbol sym, FromDeepQuery a, HasServer api context, HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (DeepQuery sym a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    If you use DeepQuery "symbol" a 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 a.

    This lets you extract an object from multiple parameters in the query string, with its fields enclosed in brackets: `/books?filter[author][name]=value`. When all the fields are known in advance, it can be done with QueryParam (it can still be tedious if you the object has many fields). When some fields are dynamic, it cannot be done with @QueryParam.

    The way the object is constructed from the extracted fields can be controlled by providing an instance on FromDeepQuery

    Example:

    type MyApi = "books" :> DeepQuery "filter" BookQuery :> Get '[JSON] [Book]
    
    server :: Server MyApi
    server = getBooksBy
      where getBooksBy :: BookQuery -> Handler [Book]
            getBooksBy query = ...filter books based on the dynamic filters provided...
  • (KnownSymbol sym, HasServer api context) => HasServer (QueryFlag sym :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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...
  • (AllCTUnrender list a, HasServer api context, SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (ReqBody' mods list a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    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 RFC 7231 section 3.1.1.5). 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...
  • (FramingUnrender framing, FromSourceIO chunk a, MimeUnrender ctype chunk, HasServer api context) => HasServer (StreamBody' mods framing ctype a :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • (AtMostOneFragment api, FragmentUnique (Fragment a1 :> api), HasServer api context) => HasServer (Fragment a1 :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Internal

    Ignore Fragment in server handlers. See https://ietf.org/rfc/rfc2616.html#section-15.1.3 for more details.

    Example:

    type MyApi = "books" :> Fragment Text :> Get '[JSON] [Book]
    
    server :: Server MyApi
    server = getBooks
      where getBooks :: Handler [Book]
            getBooks = ...return all books...
  • (ReflectMethod method, AllMime contentTypes, All (IsServerResourceWithStatus contentTypes) as, Unique (Statuses as)) => HasServer (UVerb method contentTypes as) contextDefined in servant-server-0.20.2 · Servant.Server.UVerb · orphan
  • (HasServer api context, HasContextEntry context (AuthHandler Request (AuthServerData (AuthProtect tag)))) => HasServer (AuthProtect tag :> api) contextDefined in servant-server-0.20.2 · Servant.Server.Experimental.Auth · orphan

    Known orphan instance.

  • (HasServer api ctx, HasContextEntry ctx (Acquire a)) => HasServer (WithResource a :> api) ctxDefined in servant-server-0.20.2 · Servant.Server.Internal

    If you use WithResource in one of the endpoints for your API Servant will provide the handler for this endpoint an argument of the specified type. The lifespan of this resource will be automatically managed by Servant. This resource will be created before the handler starts and it will be destoyed after it ends. A new resource is created for each request to the endpoint.

  • (HasContextEntry context (NamedContext name subContext), HasServer subApi subContext) => HasServer (WithNamedContext name subContext subApi) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • (AllCTRender ctypes a, ReflectMethod method, KnownNat status) => HasServer (Verb method status ctypes a) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • (AllCTRender ctypes a, ReflectMethod method, KnownNat status, GetHeaders (Headers h a)) => HasServer (Verb method status ctypes (Headers h a)) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • (MimeRender ctype chunk, ReflectMethod method, KnownNat status, FramingRender framing, ToSourceIO chunk a) => HasServer (Stream method status framing ctype a) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
  • (MimeRender ctype chunk, ReflectMethod method, KnownNat status, FramingRender framing, ToSourceIO chunk a, GetHeaders (Headers h a)) => HasServer (Stream method status framing ctype (Headers h a)) contextDefined in servant-server-0.20.2 · Servant.Server.Internal
datadata EmptyServer
#

Singleton type representing a server that serves an empty API.

Instances4Bounded, Enum, Eq, Show
newtypenewtype Handler a
#
Instances14Monad, Functor, MonadFail, Applicative, MonadIO, MonadCatch, …

Debugging the server layout

2 declarations
valuelayout :: HasServer api '[] => Proxy api -> Text
#

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/
│  └─ <x::Int>/
│     ├─•
│     ┆
│     └─•
├─ c/
│  └─•
┆
└─ <raw>

Explanation of symbols:

├

Normal lines reflect static branching via a table.

a/

Nodes reflect static path components.

─•

Leaves reflect endpoints.

<x::Int>/

This is a delayed capture of a single path component named

x

, of expected type

Int

.

<raw>

This is a part of the API we do not know anything about.

┆

Dashed lines suggest a dynamic choice between the part above and below. If there is a success for fatal failure in the first part, that one takes precedence. If both parts fail, the "better" error code will be returned.

Enter / hoisting server

1 declaration
valuehoistServer
  1. :: HasServer api '[]
  2. => Proxy api
  3. -> forall x. m x -> n x
  4. -> ServerT api m
  5. -> ServerT api n
#

Hoist server implementation.

Sometimes our cherished Handler monad isn't quite the type you'd like for your handlers. Maybe you want to thread some configuration in a Reader monad. Or have your types ensure that your handlers don't do any IO. Use hoistServer (a successor of now deprecated enter).

With hoistServer, you can provide a function, to convert any number of endpoints from one type constructor to another. For example

Note: Server Raw can also be entered. It will be retagged.

Example6 expressions
import Control.Monad.Readertype ReaderAPI = "ep1" :> Get '[JSON] Int :<|> "ep2" :> Get '[JSON] String :<|> Raw :<|> EmptyAPIlet readerApi = Proxy :: Proxy ReaderAPIlet readerServer = return 1797 :<|> ask :<|> Tagged (error "raw server") :<|> emptyServer :: ServerT ReaderAPI (Reader String)let nt x = return (runReader x "hi")let mainServer = hoistServer readerApi nt readerServer :: Server ReaderAPI

Functions based on mmorph

Context

4 declarations
datadata Context (contextTypes :: [Type]) where
#

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 hoistServer.) 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 heterogeneous 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 (:.):

Example1 expression
:type True :. () :. EmptyContextTrue :. () :. EmptyContext :: Context '[Bool, ()]

Constructors

Instances4Eq, Show
  • Eq (Context '[])Defined in servant-server-0.20.2 · Servant.Server.Internal.Context
  • (Eq a, Eq (Context as)) => Eq (Context (a ': as))Defined in servant-server-0.20.2 · Servant.Server.Internal.Context
  • Show (Context '[])Defined in servant-server-0.20.2 · Servant.Server.Internal.Context
  • (Show a, Show (Context as)) => Show (Context (a ': as))Defined in servant-server-0.20.2 · Servant.Server.Internal.Context
classclass HasContextEntry (context :: [Type]) val where
#

This class is used to access context entries in Contexts. getContextEntry returns the first value where the type matches:

Example1 expression
getContextEntry (True :. False :. EmptyContext) :: BoolTrue

If the Context does not contain an entry of the requested type, you'll get an error:

Example1 expression
getContextEntry (True :. False :. EmptyContext) :: String......No instance for ...HasContextEntry '[] [Char]......

Methods

Instances2HasContextEntry
familytype family (.++) (l1 :: [Type]) (l2 :: [Type]) :: [Type] where
#

Append two type-level lists.

Hint: import it as

import Servant.Server (type (.++))

Equations

  • (.++) '[] a = a
  • (.++) (a ': as) b = a ': as .++ b

NamedContext

datadata NamedContext (name :: Symbol) (subContext :: [Type])
#

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.

Constructors

valuedescendIntoNamedContext
  1. :: HasContextEntry context (NamedContext name subContext)
  2. => Proxy name
  3. -> Context context
  4. -> Context subContext
#

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:

Example6 expressions
:set -XFlexibleContextslet subContext = True :. EmptyContext:type subContextsubContext :: Context '[Bool]let parentContext = False :. (NamedContext subContext :: NamedContext "subContext" '[Bool]) :. EmptyContext:type parentContextparentContext :: Context '[Bool, NamedContext "subContext" '[Bool]]descendIntoNamedContext (Proxy :: Proxy "subContext") parentContext :: Context '[Bool]True :. EmptyContext

Basic Authentication

2 declarations
newtypenewtype BasicAuthCheck usr
#

Datatype wrapping a function used to check authentication.

Instances3Functor, Generic, Rep
datadata BasicAuthResult usr
#

servant-server's current implementation of basic authentication is not immune to certain kinds of timing attacks. Decoding payloads does not take a fixed amount of time.

The result of authentication/authorization

Instances6Functor, Eq, Read, Show, Generic, Rep

General Authentication

0 declarations

Default error type

1 declaration
datadata ServerError
#
Instances5Eq, Read, Show, Exception, MonadError

3XX

valueerr300 :: ServerError
#

err300 Multiple Choices

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err300 { errBody = "I can't choose." }
valueerr301 :: ServerError
#

err301 Moved Permanently

Example:

failingHandler :: Handler ()
failingHandler = throwError err301
valueerr304 :: ServerError
#

err304 Not Modified

Example:

failingHandler :: Handler ()
failingHandler = throwError err304
valueerr307 :: ServerError
#

err307 Temporary Redirect

Example:

failingHandler :: Handler ()
failingHandler = throwError err307

4XX

valueerr400 :: ServerError
#

err400 Bad Request

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err400 { errBody = "Your request makes no sense to me." }
valueerr401 :: ServerError
#

err401 Unauthorized

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err401 { errBody = "Your credentials are invalid." }
valueerr402 :: ServerError
#

err402 Payment Required

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err402 { errBody = "You have 0 credits. Please give me $$$." }
valueerr403 :: ServerError
#

err403 Forbidden

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err403 { errBody = "Please login first." }
valueerr404 :: ServerError
#

err404 Not Found

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err404 { errBody = "Are you lost?" }
valueerr405 :: ServerError
#

err405 Method Not Allowed

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err405 { errBody = "Your account privileges does not allow for this.  Please pay $$$." }
valueerr406 :: ServerError
#

err406 Not Acceptable

Example:

failingHandler :: Handler ()
failingHandler = throwError err406
valueerr407 :: ServerError
#

err407 Proxy Authentication Required

Example:

failingHandler :: Handler ()
failingHandler = throwError err407
valueerr409 :: ServerError
#

err409 Conflict

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
valueerr410 :: ServerError
#

err410 Gone

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
valueerr411 :: ServerError
#

err411 Length Required

Example:

failingHandler :: Handler ()
failingHandler = throwError err411
valueerr412 :: ServerError
#

err412 Precondition Failed

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
valueerr413 :: ServerError
#

err413 Request Entity Too Large

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err413 { errBody = "Request exceeded 64k." }
valueerr414 :: ServerError
#

err414 Request-URI Too Large

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err414 { errBody = "Maximum length is 64." }
valueerr415 :: ServerError
#

err415 Unsupported Media Type

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err415 { errBody = "Supported media types:  gif, png" }
valueerr416 :: ServerError
#

err416 Request range not satisfiable

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err416 { errBody = "Valid range is [0, 424242]." }
valueerr417 :: ServerError
#

err417 Expectation Failed

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err417 { errBody = "I found a quux in the request.  This isn't going to work." }
valueerr418 :: ServerError
#

err418 Expectation Failed

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err418 { errBody = "Apologies, this is not a webserver but a teapot." }
valueerr422 :: ServerError
#

err422 Unprocessable Entity

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err422 { errBody = "I understood your request, but can't process it." }
valueerr429 :: ServerError
#

err429 Too Many Requests

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err429 { errBody = "You have sent too many requests in a short period of time." }

5XX

valueerr500 :: ServerError
#

err500 Internal Server Error

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err500 { errBody = "Exception in module A.B.C:55.  Have a great day!" }
valueerr501 :: ServerError
#

err501 Not Implemented

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
valueerr502 :: ServerError
#

err502 Bad Gateway

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err502 { errBody = "Tried gateway foo, bar, and baz.  None responded." }
valueerr503 :: ServerError
#

err503 Service Unavailable

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err503 { errBody = "We're rewriting in PHP." }
valueerr504 :: ServerError
#

err504 Gateway Time-out

Example:

failingHandler :: Handler ()
failingHandler = throwError $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
valueerr505 :: ServerError
#

err505 HTTP Version not supported

Example usage:

failingHandler :: Handler ()
failingHandler = throwError $ err505 { errBody = "I support HTTP/4.0 only." }

Formatting of errors from combinators

10 declarations

You can configure how Servant will render errors that occur while parsing the request.

A custom formatter for errors produced by parsing combinators like ReqBody or Capture.

A TypeRep argument described the concrete combinator that raised the error, allowing formatter to customize the message for different combinators.

A full Request is also passed so that the formatter can react to Accept header, for example.

Re-exports

2 declarations

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")
Instances2ToApplication
  • ToApplication ApplicationDefined in wai-extra-3.1.16 · Network.Wai.UrlMap
  • ToApplication UrlMapDefined in wai-extra-3.1.16 · Network.Wai.UrlMap
newtypenewtype Tagged (s :: k) b
#

A Tagged s b value is a value b with an attached phantom type s. This can be used in place of the more traditional but less safe idiom of passing in an undefined value with the type, because unlike an (s -> b), a Tagged s b can't try to use the argument s as a real value.

Moreover, you don't have to rely on the compiler to inline away the extra argument, because the newtype is "free"

Tagged has kind k -> * -> * if the compiler supports PolyKinds, therefore there is an extra k showing in the instance haddocks that may cause confusion.

Constructors

Instances78Semigroupoid, Generic1, FoldableWithIndex, FunctorWithIndex, TraversableWithIndex, RepeatWithIndex, …