HORIZON HASKELLDocslts/ghc-10.0.xfc4e5982026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · fc4e598 · 2026-10-11

Moduleservant-0.20.3.0Haskell2010

Servant.API.MultiVerb

MultiVerb is a part of the type-level eDSL that allows you to express complex routes while retaining a high level of precision with good ergonomics.

  • 12 types
  • 5 classes
  • 3 values
  • Packageservant-0.20.3.0
  • Exports23
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceMultiVerb.hs

MultiVerb types

2 declarations
datadata MultiVerb (method :: StdMethod) (requestMimeTypes :: k) (as :: [Type]) responses
#

MultiVerb produces an endpoint which can return multiple values with various content types and status codes. It is similar to UVerb and behaves similarly, but it has some important differences:

  • Descriptions and statuses can be attached to individual responses without using wrapper types and without affecting the handler return type.

  • The return type of the handler can be decoupled from the types of the individual responses. One can use a Union type just like for UVerb, but MultiVerb also supports using an arbitrary type with an AsUnion instance. Each response is responsible for their content type.

  • Headers can be attached to individual responses, also without affecting the handler return type.

Example

Let us create an endpoint that captures an Int and has the following logic:

  • If the number is negative, we return status code 400 and an empty body;

  • If the number is even, we return a Bool in the response body;

  • If the number is odd, we return another Int in the response body.

 import qualified Generics.SOP as GSOP
-- All possible HTTP responses
type Responses =
  '[ type RespondEmpty 400 "Negative"
   , type Respond 200 "Even number" Bool
   , type Respond 200 "Odd number" Int
   ]

-- All possible return types
data Result
  = NegativeNumber
  | Odd Int
  | Even Bool
  deriving stock (Generic)
  deriving (AsUnion Responses)
    via GenericAsUnion Responses Result

instance GSOP.Generic Result

These deriving statements above tie together the responses and the return values, and the order in which they are defined matters. For instance, if Even and Odd had switched places in the definition of Result, this would provoke an error:

• No instance for ‘AsConstructor
    ((:) @Type Int ('[] @Type)) (Respond 200 "Even number" Bool)’
        arising from the 'deriving' clause of a data type declaration

If you would prefer to write an intance of AsUnion by yourself, read more in the typeclass' documentation.

Finally, let us write our endpoint description:

type MultipleChoicesInt =
  Capture "int" Int
  :> MultiVerb
    'GET
    '[JSON]
    Responses
    Result
Instances2HasLink, MkLink
  • HasLink (MultiVerb method cs as r)Defined in servant-0.20.3.0 · Servant.Links
  • type MkLink (MultiVerb method cs as r) a = aDefined in servant-0.20.3.0 · Servant.Links

Response types

4 declarations
datadata Respond (s :: Nat) (description :: Symbol) a
#

A type to describe a MultiVerb response.

Includes status code, description, and return type. The content type of the response is determined dynamically using the accept header and the list of supported content types specified in the containing MultiVerb type.

Instances2AsConstructor, ResponseType
  • AsConstructor '[a] (Respond code description a)Defined in servant-0.20.3.0 · Servant.API.MultiVerb
  • type ResponseType (Respond s description a) = aDefined in servant-0.20.3.0 · Servant.API.MultiVerb
datadata RespondAs (responseContentType :: k) (s :: Nat) (description :: Symbol) a
#

A type to describe a MultiVerb response with a fixed content type.

Similar to Respond, but hardcodes the content type to be used for generating the response. This content type is distinct from the one given to MultiVerb, as it dictactes the response's content type, not the content type request that is to be accepted.

Instances4AsUnion, AsConstructor, ResponseType
  • AsConstructor '[] (RespondEmpty code description)Defined in servant-0.20.3.0 · Servant.API.MultiVerb
  • AsUnion '[RespondEmpty s1 desc1, RespondEmpty s2 desc2] BoolDefined in servant-0.20.3.0 · Servant.API.MultiVerb

    A handler for a pair of empty responses can be implemented simply by returning a boolean value. The convention is that the "failure" case, normally represented by False, corresponds to the first response.

  • AsConstructor '[a] (RespondAs responseContentTypes code description a)Defined in servant-0.20.3.0 · Servant.API.MultiVerb
  • type ResponseType (RespondAs responseContentType s description a) = aDefined in servant-0.20.3.0 · Servant.API.MultiVerb
datadata RespondStreaming (s :: Nat) (description :: Symbol) framing ct
#

A type to describe a streaming MultiVerb response.

Includes status code, description, framing strategy and content type. Note that the handler return type is hardcoded to be 'SourceIO ByteString'.

Instances1ResponseType

Headers

6 declarations
datadata WithHeaders (headers :: [Type]) returnType response
#

This type adds response headers to a MultiVerb response.

Instances2AsConstructor, ResponseType
classclass AsHeaders (headers :: [Type]) response returnType where
#

This is used to convert a response containing headers to a custom type including the information in the headers.

If you need to send a combination of headers and response that is not provided by Servant, you can cwrite your own instance. Take example on the ones provided.

Methods

Instances3AsHeaders
  • AsHeaders '[a] () aDefined in servant-0.20.3.0 · Servant.API.MultiVerb

    Single-header empty response

  • AsHeaders '[a, b] () (a, b)Defined in servant-0.20.3.0 · Servant.API.MultiVerb

    Two headers and an empty response, return value is a tuple of the response and the header

  • AsHeaders '[h] a (a, h)Defined in servant-0.20.3.0 · Servant.API.MultiVerb

    Single-header non-empty response, return value is a tuple of the response and the header

classclass ServantHeader (h :: k) (name :: Symbol) x | h -> name x where
#

Methods

Instances3ServantHeader

Unions of responses

5 declarations
classclass AsUnion (as :: [Type]) r where
#

This class is used to convert a handler return type to a union type including all possible responses of a MultiVerb endpoint.

Any glue code necessary to convert application types to and from the canonical Union type corresponding to a MultiVerb endpoint should be packaged into an AsUnion instance.

Example

Let us take the example endpoint from the MultiVerb documentation. There, we derived the AsUnion instance with the help of Generics. The manual way of implementing the instance is:

instance AsUnion Responses Result where
  toUnion NegativeNumber = Z (I ())
  toUnion (Even b) = S (Z (I b))
  toUnion (Odd i) = S (S (Z (I i)))

  fromUnion       (Z (I ())) = NegativeNumber
  fromUnion    (S (Z (I b))) = Even b
  fromUnion (S (S (Z (I i)))) = Odd i
  fromUnion (S (S (S x))) = case x of {}

The last fromUnion equation is here to please the pattern checker.

Methods

Instances5AsUnion
  • rs ~ ResponseTypes as => AsUnion as (Union rs)Defined in servant-0.20.3.0 · Servant.API.MultiVerb

    Unions can be used directly as handler return types using this trivial instance.

  • (Code a ~ xss, Generic a, AsConstructors xss rs) => AsUnion rs (GenericAsUnion rs a)Defined in servant-0.20.3.0 · Servant.API.MultiVerb
  • AsUnion '[RespondEmpty s1 desc1, RespondEmpty s2 desc2] BoolDefined in servant-0.20.3.0 · Servant.API.MultiVerb

    A handler for a pair of empty responses can be implemented simply by returning a boolean value. The convention is that the "failure" case, normally represented by False, corresponds to the first response.

  • ResponseType r ~ a => AsUnion '[r] aDefined in servant-0.20.3.0 · Servant.API.MultiVerb

    A handler with a single response.

  • (ResponseType r1 ~ (), ResponseType r2 ~ a) => AsUnion '[r1, r2] (Maybe a)Defined in servant-0.20.3.0 · Servant.API.MultiVerb

    A handler for a pair of responses where the first is empty can be implemented simply by returning a Maybe value. The convention is that the "failure" case, normally represented by Nothing, corresponds to the first response.

Internal machinery

6 declarations
classclass AsConstructor (xs :: [Type]) r where
#

This class can be instantiated to get automatic derivation of AsUnion instances via GenericAsUnion. The idea is that one has to make sure that for each response r in a MultiVerb endpoint, there is an instance of AsConstructor xs r for some xs, and that the list xss of all the corresponding xs is equal to Code of the handler type. Then one can write: @ type Responses = ... data Result = ... deriving stock (Generic) deriving (AsUnion Responses) via (GenericAsUnion Responses Result)

instance GSOP.Generic Result @ and get an AsUnion instance for free.

There are a few predefined instances for constructors taking a single type corresponding to a simple response, and for empty responses, but in more general cases one either has to define an AsConstructor instance by hand, or derive it via GenericAsConstructor.

Instances5AsConstructor
familytype family ResponseType a
#
Instances5ResponseType
datadata UnrenderResult a
#

The result of parsing a response as a union alternative of type a.

StatusMismatch indicates that the response does not refer to the given alternative, because the status code does not match the one produced by that alternative.

UnrenderError and UnrenderSuccess represent respectively a failing and successful parse of the response body as a value of type a.

The UnrenderResult type constructor has monad and alternative instances corresponding to those of 'Either (Maybe (Last String)) a'.

Instances7Monad, Functor, Applicative, Alternative, MonadPlus, Eq, …