Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- serve :: HasServer api '[] => Proxy api -> Server api -> Application
- serveWithContext :: (HasServer api context, HasContextEntry (context .++ DefaultErrorFormatters) ErrorFormatters) => Proxy api -> Context context -> Server api -> Application
- toApplication :: RoutingApplication -> Application
- class HasServer api context where
- type Server api = ServerT api Handler
- data EmptyServer
- emptyServer :: ServerT EmptyAPI m
- newtype Handler a = Handler {
- runHandler' :: ExceptT ServerError IO a
- runHandler :: Handler a -> IO (Either ServerError a)
- layout :: HasServer api '[] => Proxy api -> Text
- layoutWithContext :: HasServer api context => Proxy api -> Context context -> Text
- hoistServer :: HasServer api '[] => Proxy api -> (forall x. m x -> n x) -> ServerT api m -> ServerT api n
- tweakResponse :: (RouteResult Response -> RouteResult Response) -> Router env -> Router env
- data Context contextTypes where
- EmptyContext :: Context '[]
- (:.) :: x -> Context xs -> Context (x ': xs)
- class HasContextEntry (context :: [*]) (val :: *) where
- getContextEntry :: Context context -> val
- type family (l1 :: [*]) .++ (l2 :: [*]) where ...
- (.++) :: Context l1 -> Context l2 -> Context (l1 .++ l2)
- data NamedContext (name :: Symbol) (subContext :: [*]) = NamedContext (Context subContext)
- descendIntoNamedContext :: forall context name subContext. HasContextEntry context (NamedContext name subContext) => Proxy (name :: Symbol) -> Context context -> Context subContext
- newtype BasicAuthCheck usr = BasicAuthCheck {
- unBasicAuthCheck :: BasicAuthData -> IO (BasicAuthResult usr)
- data BasicAuthResult usr
- = Unauthorized
- | BadPassword
- | NoSuchUser
- | Authorized usr
- data ServerError = ServerError {
- errHTTPCode :: Int
- errReasonPhrase :: String
- errBody :: ByteString
- errHeaders :: [Header]
- err300 :: ServerError
- err301 :: ServerError
- err302 :: ServerError
- err303 :: ServerError
- err304 :: ServerError
- err305 :: ServerError
- err307 :: ServerError
- err400 :: ServerError
- err401 :: ServerError
- err402 :: ServerError
- err403 :: ServerError
- err404 :: ServerError
- err405 :: ServerError
- err406 :: ServerError
- err407 :: ServerError
- err409 :: ServerError
- err410 :: ServerError
- err411 :: ServerError
- err412 :: ServerError
- err413 :: ServerError
- err414 :: ServerError
- err415 :: ServerError
- err416 :: ServerError
- err417 :: ServerError
- err418 :: ServerError
- err422 :: ServerError
- err500 :: ServerError
- err501 :: ServerError
- err502 :: ServerError
- err503 :: ServerError
- err504 :: ServerError
- err505 :: ServerError
- type ErrorFormatter = TypeRep -> Request -> String -> ServerError
- type NotFoundErrorFormatter = Request -> ServerError
- data ErrorFormatters
- bodyParserErrorFormatter :: ErrorFormatters -> ErrorFormatter
- urlParseErrorFormatter :: ErrorFormatters -> ErrorFormatter
- headerParseErrorFormatter :: ErrorFormatters -> ErrorFormatter
- notFoundErrorFormatter :: ErrorFormatters -> NotFoundErrorFormatter
- type DefaultErrorFormatters = '[ErrorFormatters]
- defaultErrorFormatters :: ErrorFormatters
- getAcceptHeader :: Request -> AcceptHeader
- type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
- newtype Tagged (s :: k) b = Tagged {
- unTagged :: b
- module Servant.Server.UVerb
Run a wai application from an API
serve :: HasServer api '[] => Proxy api -> Server api -> Application Source #
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
serveWithContext :: (HasServer api context, HasContextEntry (context .++ DefaultErrorFormatters) ErrorFormatters) => Proxy api -> Context context -> Server api -> Application Source #
Like serve
, but allows you to pass custom context.
defaultErrorFormatters
will always be appended to the end of the passed context,
but if you pass your own formatter, it will override the default one.
Construct a wai Application from an API
Handlers for all standard combinators
class HasServer api context where Source #
route :: Proxy api -> Context context -> Delayed env (Server api) -> Router env Source #
hoistServerWithContext :: Proxy api -> Proxy context -> (forall x. m x -> n x) -> ServerT api m -> ServerT api n Source #
Instances
HasServer Raw context Source # | 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 EmptyAPI context Source # | The server for an type MyApi = "nothing" :> EmptyApi server :: Server MyApi server = emptyServer |
Defined in Servant.Server.Internal | |
(TypeError (HasServerArrowTypeError a b) :: Constraint) => HasServer (a -> b :: Type) context Source # | This instance prevents from accidentally using
|
Defined in Servant.Server.Internal | |
ReflectMethod method => HasServer (NoContentVerb method :: Type) context Source # | |
Defined in Servant.Server.Internal type ServerT (NoContentVerb method) m Source # route :: Proxy (NoContentVerb method) -> Context context -> Delayed env (Server (NoContentVerb method)) -> Router env Source # hoistServerWithContext :: Proxy (NoContentVerb method) -> Proxy context -> (forall x. m x -> n x) -> ServerT (NoContentVerb method) m -> ServerT (NoContentVerb method) n Source # | |
(HasServer a context, HasServer b context) => HasServer (a :<|> b :: Type) context Source # | A server for 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 = ... |
Defined in Servant.Server.Internal | |
(HasContextEntry context (NamedContext name subContext), HasServer subApi subContext) => HasServer (WithNamedContext name subContext subApi :: Type) context Source # | |
Defined in Servant.Server.Internal type ServerT (WithNamedContext name subContext subApi) m Source # route :: Proxy (WithNamedContext name subContext subApi) -> Context context -> Delayed env (Server (WithNamedContext name subContext subApi)) -> Router env Source # hoistServerWithContext :: Proxy (WithNamedContext name subContext subApi) -> Proxy context -> (forall x. m x -> n x) -> ServerT (WithNamedContext name subContext subApi) m -> ServerT (WithNamedContext name subContext subApi) n Source # | |
(ReflectMethod method, AllMime contentTypes, All (IsServerResource contentTypes) as, Unique (Statuses as)) => HasServer (UVerb method contentTypes as :: Type) context Source # | |
Defined in Servant.Server.UVerb route :: Proxy (UVerb method contentTypes as) -> Context context -> Delayed env (Server (UVerb method contentTypes as)) -> Router env Source # hoistServerWithContext :: Proxy (UVerb method contentTypes as) -> Proxy context -> (forall x. m x -> n x) -> ServerT (UVerb method contentTypes as) m -> ServerT (UVerb method contentTypes as) n Source # | |
(TypeError (HasServerArrowKindError arr) :: Constraint) => HasServer (arr :> api :: Type) context Source # | This instance catches mistakes when there are non-saturated
type applications on LHS of
|
Defined in Servant.Server.Internal | |
HasServer api context => HasServer (HttpVersion :> api :: Type) context Source # | |
Defined in Servant.Server.Internal type ServerT (HttpVersion :> api) m Source # route :: Proxy (HttpVersion :> api) -> Context context -> Delayed env (Server (HttpVersion :> api)) -> Router env Source # hoistServerWithContext :: Proxy (HttpVersion :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (HttpVersion :> api) m -> ServerT (HttpVersion :> api) n Source # | |
(FramingUnrender framing, FromSourceIO chunk a, MimeUnrender ctype chunk, HasServer api context) => HasServer (StreamBody' mods framing ctype a :> api :: Type) context Source # | |
Defined in Servant.Server.Internal type ServerT (StreamBody' mods framing ctype a :> api) m Source # route :: Proxy (StreamBody' mods framing ctype a :> api) -> Context context -> Delayed env (Server (StreamBody' mods framing ctype a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (StreamBody' mods framing ctype a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (StreamBody' mods framing ctype a :> api) m -> ServerT (StreamBody' mods framing ctype a :> api) n Source # | |
(AllCTUnrender list a, HasServer api context, SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (ReqBody' mods list a :> api :: Type) context Source # | If you use All it asks is for a 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... |
Defined in Servant.Server.Internal route :: Proxy (ReqBody' mods list a :> api) -> Context context -> Delayed env (Server (ReqBody' mods list a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (ReqBody' mods list a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (ReqBody' mods list a :> api) m -> ServerT (ReqBody' mods list a :> api) n Source # | |
HasServer api context => HasServer (RemoteHost :> api :: Type) context Source # | |
Defined in Servant.Server.Internal type ServerT (RemoteHost :> api) m Source # route :: Proxy (RemoteHost :> api) -> Context context -> Delayed env (Server (RemoteHost :> api)) -> Router env Source # hoistServerWithContext :: Proxy (RemoteHost :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (RemoteHost :> api) m -> ServerT (RemoteHost :> api) n Source # | |
(KnownSymbol sym, FromHttpApiData a, HasServer api context, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (QueryParam' mods sym a :> api :: Type) context Source # | If you use 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 You can control how it'll be converted from 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... |
Defined in Servant.Server.Internal type ServerT (QueryParam' mods sym a :> api) m Source # route :: Proxy (QueryParam' mods sym a :> api) -> Context context -> Delayed env (Server (QueryParam' mods sym a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (QueryParam' mods sym a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (QueryParam' mods sym a :> api) m -> ServerT (QueryParam' mods sym a :> api) n Source # | |
(KnownSymbol sym, FromHttpApiData a, HasServer api context, HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (QueryParams sym a :> api :: Type) context Source # | If you use This lets servant worry about looking up 0 or more values in the query string
associated to You can control how the individual values are converted from 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... |
Defined in Servant.Server.Internal type ServerT (QueryParams sym a :> api) m Source # route :: Proxy (QueryParams sym a :> api) -> Context context -> Delayed env (Server (QueryParams sym a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (QueryParams sym a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (QueryParams sym a :> api) m -> ServerT (QueryParams sym a :> api) n Source # | |
(KnownSymbol sym, HasServer api context) => HasServer (QueryFlag sym :> api :: Type) context Source # | If you use 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... |
Defined in Servant.Server.Internal route :: Proxy (QueryFlag sym :> api) -> Context context -> Delayed env (Server (QueryFlag sym :> api)) -> Router env Source # hoistServerWithContext :: Proxy (QueryFlag sym :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (QueryFlag sym :> api) m -> ServerT (QueryFlag sym :> api) n Source # | |
(KnownSymbol sym, FromHttpApiData a, HasServer api context, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (Header' mods sym a :> api :: Type) context Source # | If you use All it asks is for a 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 |
Defined in Servant.Server.Internal route :: Proxy (Header' mods sym a :> api) -> Context context -> Delayed env (Server (Header' mods sym a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (Header' mods sym a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (Header' mods sym a :> api) m -> ServerT (Header' mods sym a :> api) n Source # | |
HasServer api context => HasServer (IsSecure :> api :: Type) context Source # | |
Defined in Servant.Server.Internal | |
(AtLeastOneFragment api, FragmentUnique (Fragment a1 :> api), HasServer api context) => HasServer (Fragment a1 :> api :: Type) context Source # | Ignore Example: type MyApi = "books" :> Fragment Text :> Get '[JSON] [Book] server :: Server MyApi server = getBooks where getBooks :: Handler [Book] getBooks = ...return all books... |
Defined in Servant.Server.Internal | |
(HasServer api context, HasContextEntry context (AuthHandler Request (AuthServerData (AuthProtect tag)))) => HasServer (AuthProtect tag :> api :: Type) context Source # | Known orphan instance. |
Defined in Servant.Server.Experimental.Auth type ServerT (AuthProtect tag :> api) m Source # route :: Proxy (AuthProtect tag :> api) -> Context context -> Delayed env (Server (AuthProtect tag :> api)) -> Router env Source # hoistServerWithContext :: Proxy (AuthProtect tag :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (AuthProtect tag :> api) m -> ServerT (AuthProtect tag :> api) n Source # | |
HasServer api ctx => HasServer (Summary desc :> api :: Type) ctx Source # | Ignore |
Defined in Servant.Server.Internal | |
HasServer api ctx => HasServer (Description desc :> api :: Type) ctx Source # | Ignore |
Defined in Servant.Server.Internal type ServerT (Description desc :> api) m Source # route :: Proxy (Description desc :> api) -> Context ctx -> Delayed env (Server (Description desc :> api)) -> Router env Source # hoistServerWithContext :: Proxy (Description desc :> api) -> Proxy ctx -> (forall x. m x -> n x) -> ServerT (Description desc :> api) m -> ServerT (Description desc :> api) n Source # | |
(KnownSymbol capture, FromHttpApiData a, HasServer api context, SBoolI (FoldLenient mods), HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (Capture' mods capture a :> api :: Type) context Source # | If you use You can control how it'll be converted from Example: type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book server :: Server MyApi server = getBook where getBook :: Text -> Handler Book getBook isbn = ... |
Defined in Servant.Server.Internal route :: Proxy (Capture' mods capture a :> api) -> Context context -> Delayed env (Server (Capture' mods capture a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (Capture' mods capture a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (Capture' mods capture a :> api) m -> ServerT (Capture' mods capture a :> api) n Source # | |
(KnownSymbol capture, FromHttpApiData a, HasServer api context, HasContextEntry (MkContextWithErrorFormatter context) ErrorFormatters) => HasServer (CaptureAll capture a :> api :: Type) context Source # | If you use You can control how they'll be converted from Example: type MyApi = "src" :> CaptureAll "segments" Text :> Get '[JSON] SourceFile server :: Server MyApi server = getSourceFile where getSourceFile :: [Text] -> Handler Book getSourceFile pathSegments = ... |
Defined in Servant.Server.Internal type ServerT (CaptureAll capture a :> api) m Source # route :: Proxy (CaptureAll capture a :> api) -> Context context -> Delayed env (Server (CaptureAll capture a :> api)) -> Router env Source # hoistServerWithContext :: Proxy (CaptureAll capture a :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (CaptureAll capture a :> api) m -> ServerT (CaptureAll capture a :> api) n Source # | |
(KnownSymbol realm, HasServer api context, HasContextEntry context (BasicAuthCheck usr)) => HasServer (BasicAuth realm usr :> api :: Type) context Source # | Basic Authentication |
Defined in Servant.Server.Internal route :: Proxy (BasicAuth realm usr :> api) -> Context context -> Delayed env (Server (BasicAuth realm usr :> api)) -> Router env Source # hoistServerWithContext :: Proxy (BasicAuth realm usr :> api) -> Proxy context -> (forall x. m x -> n x) -> ServerT (BasicAuth realm usr :> api) m -> ServerT (BasicAuth realm usr :> api) n Source # | |
HasServer api context => HasServer (Vault :> api :: Type) context Source # | |
Defined in Servant.Server.Internal | |
(KnownSymbol path, HasServer api context) => HasServer (path :> api :: Type) context Source # | Make sure the incoming request starts with |
Defined in Servant.Server.Internal | |
(AllCTRender ctypes a, ReflectMethod method, KnownNat status, GetHeaders (Headers h a)) => HasServer (Verb method status ctypes (Headers h a) :: Type) context Source # | |
Defined in Servant.Server.Internal route :: Proxy (Verb method status ctypes (Headers h a)) -> Context context -> Delayed env (Server (Verb method status ctypes (Headers h a))) -> Router env Source # hoistServerWithContext :: Proxy (Verb method status ctypes (Headers h a)) -> Proxy context -> (forall x. m x -> n x) -> ServerT (Verb method status ctypes (Headers h a)) m -> ServerT (Verb method status ctypes (Headers h a)) n Source # | |
(AllCTRender ctypes a, ReflectMethod method, KnownNat status) => HasServer (Verb method status ctypes a :: Type) context Source # | |
Defined in Servant.Server.Internal route :: Proxy (Verb method status ctypes a) -> Context context -> Delayed env (Server (Verb method status ctypes a)) -> Router env Source # hoistServerWithContext :: Proxy (Verb method status ctypes a) -> Proxy context -> (forall x. m x -> n x) -> ServerT (Verb method status ctypes a) m -> ServerT (Verb method status ctypes a) n Source # | |
(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) :: Type) context Source # | |
Defined in Servant.Server.Internal route :: Proxy (Stream method status framing ctype (Headers h a)) -> Context context -> Delayed env (Server (Stream method status framing ctype (Headers h a))) -> Router env Source # hoistServerWithContext :: Proxy (Stream method status framing ctype (Headers h a)) -> Proxy context -> (forall x. m x -> n x) -> ServerT (Stream method status framing ctype (Headers h a)) m -> ServerT (Stream method status framing ctype (Headers h a)) n Source # | |
(MimeRender ctype chunk, ReflectMethod method, KnownNat status, FramingRender framing, ToSourceIO chunk a) => HasServer (Stream method status framing ctype a :: Type) context Source # | |
Defined in Servant.Server.Internal route :: Proxy (Stream method status framing ctype a) -> Context context -> Delayed env (Server (Stream method status framing ctype a)) -> Router env Source # hoistServerWithContext :: Proxy (Stream method status framing ctype a) -> Proxy context -> (forall x. m x -> n x) -> ServerT (Stream method status framing ctype a) m -> ServerT (Stream method status framing ctype a) n Source # |
data EmptyServer Source #
Singleton type representing a server that serves an empty API.
Instances
Bounded EmptyServer Source # | |
Defined in Servant.Server.Internal minBound :: EmptyServer # maxBound :: EmptyServer # | |
Enum EmptyServer Source # | |
Defined in Servant.Server.Internal succ :: EmptyServer -> EmptyServer # pred :: EmptyServer -> EmptyServer # toEnum :: Int -> EmptyServer # fromEnum :: EmptyServer -> Int # enumFrom :: EmptyServer -> [EmptyServer] # enumFromThen :: EmptyServer -> EmptyServer -> [EmptyServer] # enumFromTo :: EmptyServer -> EmptyServer -> [EmptyServer] # enumFromThenTo :: EmptyServer -> EmptyServer -> EmptyServer -> [EmptyServer] # | |
Eq EmptyServer Source # | |
Defined in Servant.Server.Internal (==) :: EmptyServer -> EmptyServer -> Bool # (/=) :: EmptyServer -> EmptyServer -> Bool # | |
Show EmptyServer Source # | |
Defined in Servant.Server.Internal showsPrec :: Int -> EmptyServer -> ShowS # show :: EmptyServer -> String # showList :: [EmptyServer] -> ShowS # |
Instances
runHandler :: Handler a -> IO (Either ServerError a) Source #
Debugging the server layout
layout :: HasServer api '[] => Proxy api -> Text Source #
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:
├
- Normal lines reflect static branching via a table.
a/
- Nodes reflect static path components.
─•
- Leaves reflect endpoints.
<capture>/
- This is a delayed capture of a path component.
<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
hoistServer :: HasServer api '[] => Proxy api -> (forall x. m x -> n x) -> ServerT api m -> ServerT api n Source #
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.
>>>
import Control.Monad.Reader
>>>
type ReaderAPI = "ep1" :> Get '[JSON] Int :<|> "ep2" :> Get '[JSON] String :<|> Raw :<|> EmptyAPI
>>>
let readerApi = Proxy :: Proxy ReaderAPI
>>>
let 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
tweakResponse :: (RouteResult Response -> RouteResult Response) -> Router env -> Router env Source #
Apply a transformation to the response of a Router
.
Context
data Context contextTypes where Source #
Context
s 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 (
::.
)
>>>
:type True :. () :. EmptyContext
True :. () :. EmptyContext :: Context '[Bool, ()]
EmptyContext :: Context '[] | |
(:.) :: x -> Context xs -> Context (x ': xs) infixr 5 |
class HasContextEntry (context :: [*]) (val :: *) where Source #
This class is used to access context entries in Context
s. 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]) ...
getContextEntry :: Context context -> val Source #
Instances
HasContextEntry (val ': xs) val Source # | |
Defined in Servant.Server.Internal.Context getContextEntry :: Context (val ': xs) -> val Source # | |
HasContextEntry xs val => HasContextEntry (notIt ': xs) val Source # | |
Defined in Servant.Server.Internal.Context getContextEntry :: Context (notIt ': xs) -> val Source # |
type family (l1 :: [*]) .++ (l2 :: [*]) where ... Source #
Append two type-level lists.
Hint: import it as
import Servant.Server (type (.++))
NamedContext
data NamedContext (name :: Symbol) (subContext :: [*]) Source #
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
Context
s.
NamedContext (Context subContext) |
descendIntoNamedContext :: forall context name subContext. HasContextEntry context (NamedContext name subContext) => Proxy (name :: Symbol) -> Context context -> Context subContext Source #
descendIntoNamedContext
allows you to access NamedContext
s. 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
Basic Authentication
newtype BasicAuthCheck usr Source #
Datatype wrapping a function used to check authentication.
BasicAuthCheck | |
|
Instances
Functor BasicAuthCheck Source # | |
Defined in Servant.Server.Internal.BasicAuth fmap :: (a -> b) -> BasicAuthCheck a -> BasicAuthCheck b # (<$) :: a -> BasicAuthCheck b -> BasicAuthCheck a # | |
Generic (BasicAuthCheck usr) Source # | |
Defined in Servant.Server.Internal.BasicAuth type Rep (BasicAuthCheck usr) :: Type -> Type # from :: BasicAuthCheck usr -> Rep (BasicAuthCheck usr) x # to :: Rep (BasicAuthCheck usr) x -> BasicAuthCheck usr # | |
type Rep (BasicAuthCheck usr) Source # | |
Defined in Servant.Server.Internal.BasicAuth type Rep (BasicAuthCheck usr) = D1 ('MetaData "BasicAuthCheck" "Servant.Server.Internal.BasicAuth" "servant-server-0.18.2-38izuKQ1ZUr8MIAjj3sZRb" 'True) (C1 ('MetaCons "BasicAuthCheck" 'PrefixI 'True) (S1 ('MetaSel ('Just "unBasicAuthCheck") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (BasicAuthData -> IO (BasicAuthResult usr))))) |
data BasicAuthResult usr Source #
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
Instances
General Authentication
Default error type
data ServerError Source #
ServerError | |
|
Instances
Eq ServerError Source # | |
Defined in Servant.Server.Internal.ServerError (==) :: ServerError -> ServerError -> Bool # (/=) :: ServerError -> ServerError -> Bool # | |
Read ServerError Source # | |
Defined in Servant.Server.Internal.ServerError readsPrec :: Int -> ReadS ServerError # readList :: ReadS [ServerError] # readPrec :: ReadPrec ServerError # readListPrec :: ReadPrec [ServerError] # | |
Show ServerError Source # | |
Defined in Servant.Server.Internal.ServerError showsPrec :: Int -> ServerError -> ShowS # show :: ServerError -> String # showList :: [ServerError] -> ShowS # | |
Exception ServerError Source # | |
Defined in Servant.Server.Internal.ServerError | |
MonadError ServerError Handler Source # | |
Defined in Servant.Server.Internal.Handler throwError :: ServerError -> Handler a # catchError :: Handler a -> (ServerError -> Handler a) -> Handler a # |
3XX
err300 :: ServerError Source #
err300
Multiple Choices
Example:
failingHandler :: Handler () failingHandler = throwError $ err300 { errBody = "I can't choose." }
err301 :: ServerError Source #
err302 :: ServerError Source #
err303 :: ServerError Source #
err304 :: ServerError Source #
err305 :: ServerError Source #
err307 :: ServerError Source #
4XX
err400 :: ServerError Source #
err400
Bad Request
Example:
failingHandler :: Handler () failingHandler = throwError $ err400 { errBody = "Your request makes no sense to me." }
err401 :: ServerError Source #
err401
Unauthorized
Example:
failingHandler :: Handler () failingHandler = throwError $ err401 { errBody = "Your credentials are invalid." }
err402 :: ServerError Source #
err402
Payment Required
Example:
failingHandler :: Handler () failingHandler = throwError $ err402 { errBody = "You have 0 credits. Please give me $$$." }
err403 :: ServerError Source #
err403
Forbidden
Example:
failingHandler :: Handler () failingHandler = throwError $ err403 { errBody = "Please login first." }
err404 :: ServerError Source #
err404
Not Found
Example:
failingHandler :: Handler () failingHandler = throwError $ err404 { errBody = "(╯°□°)╯︵ ┻━┻)." }
err405 :: ServerError Source #
err405
Method Not Allowed
Example:
failingHandler :: Handler () failingHandler = throwError $ err405 { errBody = "Your account privileges does not allow for this. Please pay $$$." }
err406 :: ServerError Source #
err407 :: ServerError Source #
err407
Proxy Authentication Required
Example:
failingHandler :: Handler () failingHandler = throwError err407
err409 :: ServerError Source #
err409
Conflict
Example:
failingHandler :: Handler () failingHandler = throwError $ err409 { errBody = "Transaction conflicts with 59879cb56c7c159231eeacdd503d755f7e835f74" }
err410 :: ServerError Source #
err410
Gone
Example:
failingHandler :: Handler () failingHandler = throwError $ err410 { errBody = "I know it was here at some point, but.. I blame bad luck." }
err411 :: ServerError Source #
err412 :: ServerError Source #
err412
Precondition Failed
Example:
failingHandler :: Handler () failingHandler = throwError $ err412 { errBody = "Precondition fail: x < 42 && y > 57" }
err413 :: ServerError Source #
err413
Request Entity Too Large
Example:
failingHandler :: Handler () failingHandler = throwError $ err413 { errBody = "Request exceeded 64k." }
err414 :: ServerError Source #
err414
Request-URI Too Large
Example:
failingHandler :: Handler () failingHandler = throwError $ err414 { errBody = "Maximum length is 64." }
err415 :: ServerError Source #
err415
Unsupported Media Type
Example:
failingHandler :: Handler () failingHandler = throwError $ err415 { errBody = "Supported media types: gif, png" }
err416 :: ServerError Source #
err416
Request range not satisfiable
Example:
failingHandler :: Handler () failingHandler = throwError $ err416 { errBody = "Valid range is [0, 424242]." }
err417 :: ServerError Source #
err417
Expectation Failed
Example:
failingHandler :: Handler () failingHandler = throwError $ err417 { errBody = "I found a quux in the request. This isn't going to work." }
err418 :: ServerError Source #
err418
Expectation Failed
Example:
failingHandler :: Handler () failingHandler = throwError $ err418 { errBody = "Apologies, this is not a webserver but a teapot." }
err422 :: ServerError Source #
err422
Unprocessable Entity
Example:
failingHandler :: Handler () failingHandler = throwError $ err422 { errBody = "I understood your request, but can't process it." }
5XX
err500 :: ServerError Source #
err500
Internal Server Error
Example:
failingHandler :: Handler () failingHandler = throwError $ err500 { errBody = "Exception in module A.B.C:55. Have a great day!" }
err501 :: ServerError Source #
err501
Not Implemented
Example:
failingHandler :: Handler () failingHandler = throwError $ err501 { errBody = "/v1/foo is not supported with quux in the request." }
err502 :: ServerError Source #
err502
Bad Gateway
Example:
failingHandler :: Handler () failingHandler = throwError $ err502 { errBody = "Tried gateway foo, bar, and baz. None responded." }
err503 :: ServerError Source #
err503
Service Unavailable
Example:
failingHandler :: Handler () failingHandler = throwError $ err503 { errBody = "We're rewriting in PHP." }
err504 :: ServerError Source #
err504
Gateway Time-out
Example:
failingHandler :: Handler () failingHandler = throwError $ err504 { errBody = "Backend foobar did not respond in 5 seconds." }
err505 :: ServerError Source #
err505
HTTP Version not supported
Example usage:
failingHandler :: Handler () failingHandler = throwError $ err505 { errBody = "I support HTTP/4.0 only." }
Formatting of errors from combinators
You can configure how Servant will render errors that occur while parsing the request.
type ErrorFormatter = TypeRep -> Request -> String -> ServerError Source #
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.
type NotFoundErrorFormatter = Request -> ServerError Source #
This formatter does not get neither TypeRep
nor error message.
data ErrorFormatters Source #
A collection of error formatters for different situations.
If you need to override one of them, use defaultErrorFormatters
with record update syntax.
bodyParserErrorFormatter :: ErrorFormatters -> ErrorFormatter Source #
Format error from parsing the request body.
urlParseErrorFormatter :: ErrorFormatters -> ErrorFormatter Source #
Format error from parsing url parts or query parameters.
headerParseErrorFormatter :: ErrorFormatters -> ErrorFormatter Source #
Format error from parsing request headers.
notFoundErrorFormatter :: ErrorFormatters -> NotFoundErrorFormatter Source #
Format error for not found URLs.
type DefaultErrorFormatters = '[ErrorFormatters] Source #
Context
that contains default error formatters.
defaultErrorFormatters :: ErrorFormatters Source #
Default formatters will just return HTTP 400 status code with error message as response body.
Re-exports
type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived #
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")
A
value is a value Tagged
s bb
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
can't try to use the argument Tagged
s bs
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.
Instances
Bifunctor (Tagged :: Type -> Type -> Type) | |
Bitraversable (Tagged :: Type -> Type -> Type) | |
Defined in Data.Tagged bitraverse :: Applicative f => (a -> f c) -> (b -> f d) -> Tagged a b -> f (Tagged c d) # | |
Bifoldable (Tagged :: Type -> Type -> Type) | |
Eq2 (Tagged :: Type -> Type -> Type) | |
Ord2 (Tagged :: Type -> Type -> Type) | |
Defined in Data.Tagged | |
Read2 (Tagged :: Type -> Type -> Type) | |
Defined in Data.Tagged liftReadsPrec2 :: (Int -> ReadS a) -> ReadS [a] -> (Int -> ReadS b) -> ReadS [b] -> Int -> ReadS (Tagged a b) # liftReadList2 :: (Int -> ReadS a) -> ReadS [a] -> (Int -> ReadS b) -> ReadS [b] -> ReadS [Tagged a b] # liftReadPrec2 :: ReadPrec a -> ReadPrec [a] -> ReadPrec b -> ReadPrec [b] -> ReadPrec (Tagged a b) # liftReadListPrec2 :: ReadPrec a -> ReadPrec [a] -> ReadPrec b -> ReadPrec [b] -> ReadPrec [Tagged a b] # | |
Show2 (Tagged :: Type -> Type -> Type) | |
Generic1 (Tagged s :: Type -> Type) | |
Monad (Tagged s) | |
Functor (Tagged s) | |
Applicative (Tagged s) | |
Foldable (Tagged s) | |
Defined in Data.Tagged fold :: Monoid m => Tagged s m -> m # foldMap :: Monoid m => (a -> m) -> Tagged s a -> m # foldMap' :: Monoid m => (a -> m) -> Tagged s a -> m # foldr :: (a -> b -> b) -> b -> Tagged s a -> b # foldr' :: (a -> b -> b) -> b -> Tagged s a -> b # foldl :: (b -> a -> b) -> b -> Tagged s a -> b # foldl' :: (b -> a -> b) -> b -> Tagged s a -> b # foldr1 :: (a -> a -> a) -> Tagged s a -> a # foldl1 :: (a -> a -> a) -> Tagged s a -> a # elem :: Eq a => a -> Tagged s a -> Bool # maximum :: Ord a => Tagged s a -> a # minimum :: Ord a => Tagged s a -> a # | |
Traversable (Tagged s) | |
Eq1 (Tagged s) | |
Ord1 (Tagged s) | |
Defined in Data.Tagged | |
Read1 (Tagged s) | |
Defined in Data.Tagged | |
Show1 (Tagged s) | |
Bounded b => Bounded (Tagged s b) | |
Enum a => Enum (Tagged s a) | |
Defined in Data.Tagged succ :: Tagged s a -> Tagged s a # pred :: Tagged s a -> Tagged s a # fromEnum :: Tagged s a -> Int # enumFrom :: Tagged s a -> [Tagged s a] # enumFromThen :: Tagged s a -> Tagged s a -> [Tagged s a] # enumFromTo :: Tagged s a -> Tagged s a -> [Tagged s a] # enumFromThenTo :: Tagged s a -> Tagged s a -> Tagged s a -> [Tagged s a] # | |
Eq b => Eq (Tagged s b) | |
Floating a => Floating (Tagged s a) | |
Defined in Data.Tagged exp :: Tagged s a -> Tagged s a # log :: Tagged s a -> Tagged s a # sqrt :: Tagged s a -> Tagged s a # (**) :: Tagged s a -> Tagged s a -> Tagged s a # logBase :: Tagged s a -> Tagged s a -> Tagged s a # sin :: Tagged s a -> Tagged s a # cos :: Tagged s a -> Tagged s a # tan :: Tagged s a -> Tagged s a # asin :: Tagged s a -> Tagged s a # acos :: Tagged s a -> Tagged s a # atan :: Tagged s a -> Tagged s a # sinh :: Tagged s a -> Tagged s a # cosh :: Tagged s a -> Tagged s a # tanh :: Tagged s a -> Tagged s a # asinh :: Tagged s a -> Tagged s a # acosh :: Tagged s a -> Tagged s a # atanh :: Tagged s a -> Tagged s a # log1p :: Tagged s a -> Tagged s a # expm1 :: Tagged s a -> Tagged s a # | |
Fractional a => Fractional (Tagged s a) | |
Integral a => Integral (Tagged s a) | |
Defined in Data.Tagged quot :: Tagged s a -> Tagged s a -> Tagged s a # rem :: Tagged s a -> Tagged s a -> Tagged s a # div :: Tagged s a -> Tagged s a -> Tagged s a # mod :: Tagged s a -> Tagged s a -> Tagged s a # quotRem :: Tagged s a -> Tagged s a -> (Tagged s a, Tagged s a) # divMod :: Tagged s a -> Tagged s a -> (Tagged s a, Tagged s a) # | |
(Data s, Data b) => Data (Tagged s b) | |
Defined in Data.Tagged gfoldl :: (forall d b0. Data d => c (d -> b0) -> d -> c b0) -> (forall g. g -> c g) -> Tagged s b -> c (Tagged s b) # gunfold :: (forall b0 r. Data b0 => c (b0 -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Tagged s b) # toConstr :: Tagged s b -> Constr # dataTypeOf :: Tagged s b -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Tagged s b)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Tagged s b)) # gmapT :: (forall b0. Data b0 => b0 -> b0) -> Tagged s b -> Tagged s b # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Tagged s b -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Tagged s b -> r # gmapQ :: (forall d. Data d => d -> u) -> Tagged s b -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Tagged s b -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Tagged s b -> m (Tagged s b) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Tagged s b -> m (Tagged s b) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Tagged s b -> m (Tagged s b) # | |
Num a => Num (Tagged s a) | |
Defined in Data.Tagged | |
Ord b => Ord (Tagged s b) | |
Read b => Read (Tagged s b) | |
Real a => Real (Tagged s a) | |
Defined in Data.Tagged toRational :: Tagged s a -> Rational # | |
RealFloat a => RealFloat (Tagged s a) | |
Defined in Data.Tagged floatRadix :: Tagged s a -> Integer # floatDigits :: Tagged s a -> Int # floatRange :: Tagged s a -> (Int, Int) # decodeFloat :: Tagged s a -> (Integer, Int) # encodeFloat :: Integer -> Int -> Tagged s a # exponent :: Tagged s a -> Int # significand :: Tagged s a -> Tagged s a # scaleFloat :: Int -> Tagged s a -> Tagged s a # isInfinite :: Tagged s a -> Bool # isDenormalized :: Tagged s a -> Bool # isNegativeZero :: Tagged s a -> Bool # | |
RealFrac a => RealFrac (Tagged s a) | |
Show b => Show (Tagged s b) | |
Ix b => Ix (Tagged s b) | |
Defined in Data.Tagged range :: (Tagged s b, Tagged s b) -> [Tagged s b] # index :: (Tagged s b, Tagged s b) -> Tagged s b -> Int # unsafeIndex :: (Tagged s b, Tagged s b) -> Tagged s b -> Int # inRange :: (Tagged s b, Tagged s b) -> Tagged s b -> Bool # rangeSize :: (Tagged s b, Tagged s b) -> Int # unsafeRangeSize :: (Tagged s b, Tagged s b) -> Int # | |
IsString a => IsString (Tagged s a) | |
Defined in Data.Tagged fromString :: String -> Tagged s a # | |
Generic (Tagged s b) | |
Semigroup a => Semigroup (Tagged s a) | |
(Semigroup a, Monoid a) => Monoid (Tagged s a) | |
Storable a => Storable (Tagged s a) | |
Defined in Data.Tagged | |
Bits a => Bits (Tagged s a) | |
Defined in Data.Tagged (.&.) :: Tagged s a -> Tagged s a -> Tagged s a # (.|.) :: Tagged s a -> Tagged s a -> Tagged s a # xor :: Tagged s a -> Tagged s a -> Tagged s a # complement :: Tagged s a -> Tagged s a # shift :: Tagged s a -> Int -> Tagged s a # rotate :: Tagged s a -> Int -> Tagged s a # setBit :: Tagged s a -> Int -> Tagged s a # clearBit :: Tagged s a -> Int -> Tagged s a # complementBit :: Tagged s a -> Int -> Tagged s a # testBit :: Tagged s a -> Int -> Bool # bitSizeMaybe :: Tagged s a -> Maybe Int # bitSize :: Tagged s a -> Int # isSigned :: Tagged s a -> Bool # shiftL :: Tagged s a -> Int -> Tagged s a # unsafeShiftL :: Tagged s a -> Int -> Tagged s a # shiftR :: Tagged s a -> Int -> Tagged s a # unsafeShiftR :: Tagged s a -> Int -> Tagged s a # rotateL :: Tagged s a -> Int -> Tagged s a # | |
FiniteBits a => FiniteBits (Tagged s a) | |
Defined in Data.Tagged finiteBitSize :: Tagged s a -> Int # countLeadingZeros :: Tagged s a -> Int # countTrailingZeros :: Tagged s a -> Int # | |
NFData b => NFData (Tagged s b) | |
Defined in Data.Tagged | |
ToFormKey a => ToFormKey (Tagged b a) | |
Defined in Web.Internal.FormUrlEncoded | |
FromFormKey a => FromFormKey (Tagged b a) | |
Defined in Web.Internal.FormUrlEncoded | |
ToHttpApiData a => ToHttpApiData (Tagged b a) | Note: this instance is not polykinded |
Defined in Web.Internal.HttpApiData toUrlPiece :: Tagged b a -> Text # toEncodedUrlPiece :: Tagged b a -> Builder # toHeader :: Tagged b a -> ByteString # toQueryParam :: Tagged b a -> Text # | |
FromHttpApiData a => FromHttpApiData (Tagged b a) | Note: this instance is not polykinded |
Defined in Web.Internal.HttpApiData parseUrlPiece :: Text -> Either Text (Tagged b a) # parseHeader :: ByteString -> Either Text (Tagged b a) # | |
type Rep1 (Tagged s :: Type -> Type) | |
Defined in Data.Tagged | |
type Rep (Tagged s b) | |
Defined in Data.Tagged |
module Servant.Server.UVerb