!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ None!"(3457>KLNyNormally context entries are accessed by their types. In case you need to have multiple values of the same type in your & and need to access them, we provide -. You can think of it as sub-namespaces for s.0This class is used to access context entries in s. 1 returns the first value where the type matches:7getContextEntry (True :. False :. EmptyContext) :: BoolTrueIf the G does not contain an entry of the requested type, you'll get an error:9getContextEntry (True :. False :. EmptyContext) :: String...0 No instance for (HasContextEntry '[] [Char])...4s are used to pass values to combinators. (They are nota meant to be used to pass parameters to your handlers, i.e. they should not replace any custom   %-monad-stack that you're using with T.) If you don't use combinators that require any context entries, you can just use   as always.6If you are using combinators that require a non-empty  you have to use   and pass it a 8 that contains all the values your combinators need. A [ is essentially a heterogenous list and accessing the elements is being done by type (see ). The parameter of the type Z is a type-level list reflecting the types of the contained context entries. To create a ! with entries, use the operator (): :type True :. () :. EmptyContext1True :. () :. EmptyContext :: Context '[Bool, ()]   allows you to access Qs. Usually you won't have to use it yourself but instead use a combinator like . This is how   works::set -XFlexibleContexts%let subContext = True :. EmptyContext:type subContextsubContext :: Context '[Bool]klet parentContext = False :. (NamedContext subContext :: NamedContext "subContext" '[Bool]) :. EmptyContext:type parentContextCparentContext :: Context '[Bool, NamedContext "subContext" '[Bool]]VdescendIntoNamedContext (Proxy :: Proxy "subContext") parentContext :: Context '[Bool]True :. EmptyContext      None+& !"#$%&'()*+,-./012345% !"#$%&'()*+,-./01234&5 !"#$%&'()*+,-./01234! !"#$%&'()*+,-./012345None !"*->KL6A 6Y 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: In a straight-forward implementation, the order in which we perform checks will determine the error we generate. This is because once an error occurs, we would abort and not perform any subsequent checks, but rather return the current error.This is not a necessity: we could continue doing other checks, and choose the preferred error. However, that would in general mean more checking, which leads us to the other reason. ZWe really want to avoid doing certain checks too early. For example, captures involve parsing, and are much more costly than static route matches. In particular, if several paths contain the "same" capture, we'd like as much as possible to avoid trying the same parse many times. Also tricky is the request body. Again, this involves parsing, but also, WAI makes obtaining the request body a side-effecting operation. We could/can work around this by manually caching the request body, but we'd rather keep the number of times we actually try to decode the request body to an absolute minimum.DWe prefer to have the following relative priorities of error codes: l404 405 (bad method) 401 (unauthorized) 415 (unsupported media type) 400 (bad request) 406 (not acceptable) fTherefore, while routing, we delay most checks so that they will ultimately occur in the right order.A 6A contains three delayed blocks of tests, and the actual handler: Delayed captures. These can actually cause 404, and while they're costly, they should be done first among the delayed checks (at least as long as we do not decouple the check order from the error reporting, see above). Delayed captures can provide inputs to the actual handler.Method check(s). This can cause a 405. On success, it does not provide an input for the handler. Method checks are comparatively cheap.Body and accept header checks. The request body check can cause both 400 and 415. This provides an input to the handler. The accept header check can be performed as the final computation in this block. It can cause a 406.=8The result of matching against a path in the route tree.>Keep trying other paths. The  ServantErr! should only be 404, 405 or 406.?Don't try other paths.C.Add a capture to the end of the capture block.D2Add a method check to the end of the method block.E/Add an auth check to the end of the auth block.F.Add a body check to the end of the body block.GAdd an accept header check to the end of the body block. The accept header check should occur after the body check, but this will be the case, because the accept header check is only scheduled by the method combinators.HyMany combinators extract information that is passed to the handler without the possibility of failure. In such a case, H can be used.IThe combination 'IO . RouteResult' is a monad, but we don't explicitly wrap it in a newtype in order to make it an instance. This is the  of that monad.We stop on the first error.JCommon special case of I, corresponding to liftM2.KRun a delayed server. Performs all scheduled operations in order, and passes the results from the capture and body blocks on to the actual handler.wThis should only be called once per request; otherwise the guarantees about effect and HTTP error ordering break down.LRuns a delayed server and the resulting action. Takes a continuation that lets us send a response. Also takes a continuation for how to turn the result of the delayed server into a response.6789:;<=>?@Athe request, the field pathInfo may be modified by url routingBCDEFGHIJKLM6789:;<=>?@ABCDEFGHIJKLA=>?@B6789:;<MCDEFGHIJKL6789:;<=>?@ABCDEFGHIJKLMNone+-0N:Datatype wrapping a function used to check authentication.Qservant-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/authorizationV.Internal method to make a basic-auth challengeWFind and decode an  Authorization& header from the request as Basic AuthXWRun and check basic authentication, returning the appropriate http error per the spec. NOPQRSTUVWX NOPQRSTUVWX QRSTUNOPVWXNOPQRSTUVWXNone- Y$Internal representation of a router.Z'current request is passed to the router[;first path component used for lookup and removed afterwards\;first path component used for lookup and removed afterwards].to be used for routes that match an empty path^&left-biased choice between two routers`,Apply a transformation to the response of a _.a]Smart constructor for the choice between routers. We currently optimize the following cases:7Two static routers can be joined by joining their maps.=Two dynamic routers can be joined by joining their codomains.Two ZY routers can be joined by passing them the same request and joining their codomains.A Z router can be joined with anything else by passing the same request to both but ignoring it in the component that does not need it.b%Interpret a router as an application. YZ[\]^_`abc YZ[\]^_`abc _YZ[\]^`abcYZ[\]^_`abcNone+3579>IKLNdA natural transformation from m to n . Used to h particular datatypes.iLike .mLog the contents of P with the function provided as the first argument, and return the value of the WriterT computationnLike m, but for strict WriterT.oLike mmorph's .pLike mmorph's .qLike mmorph's .rLike mmorph's .defghijklmnopqrstuvdefghijklmnopqrghvudeftsijklmnopqrdefghijklmnopqrstuvNone&'(3457>CKLN Basic Authentication+Make sure the incoming request starts with "/path"5, strip it and pass the rest of the request path to  sublayout. If you use  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  Content-Typep 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  2http://tools.ietf.org/html/rfc7231#section-3.1.1.5RFC7231u. 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 -> ExceptT ServantErr IO Book postBook book = ...insert into your db...KJust 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  "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 .Example: &type MyApi = "books" :> QueryFlag "published" :> Get '[JSON] [Book] server :: Server MyApi server = getBooks where getBooks :: Bool -> ExceptT ServantErr IO [Book] getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument... If you use  "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 [].]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 2 to your type by simply providing an instance of  for your type.Example: type MyApi = "books" :> QueryParams "authors" Text :> Get '[JSON] [Book] server :: Server MyApi server = getBooksBy where getBooksBy :: [Text] -> ExceptT ServantErr IO [Book] getBooksBy authors = ...return all books by these authors... If you use  "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  .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 ?, because it may not be there and servant would then hand you .,You can control how it'll be converted from 2 to your type by simply providing an instance of  for your type.Example: 7type MyApi = "books" :> QueryParam "author" Text :> Get '[JSON] [Book] server :: Server MyApi server = getBooksBy where getBooksBy :: Maybe Text -> ExceptT ServantErr IO [Book] getBooksBy Nothing = ...return all books... getBooksBy (Just author) = ...return books by the given author... If you use  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 u. 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  instance.Example: ]newtype Referer = Referer Text deriving (Eq, Show, FromHttpApiData, ToText) -- GET /view-my-referer type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer server :: Server MyApi server = viewReferer where viewReferer :: Referer -> ExceptT ServantErr IO referer viewReferer referer = return referer If you use  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 n. 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 2 to your type by simply providing an instance of  for your type.Example: type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book server :: Server MyApi server = getBook where getBook :: Text -> ExceptT ServantErr IO Book getBook isbn = ... A server for a  bF first tries to match the request against the route represented by a and if it fails tries b7. 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 = ...wxyz{|}~h  !"#$%&'()*+,-./012346789:;<=>?@ABCDEFGHIJKLNOPQRSTUVWXYZ[\]^_`abcwxyz{|}~xyzw{|}~wxyz{|}~ None&(4>L2 allows you to implement an API and produce a wai .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 appJ  !"#$%&'()*+,-./01234BNOPQRSTU`defhijklmnopqrwxyzJBxyzwhdefijklnmopqr` NOPQRSTU !"#$%&'()*+,-./01234 None2Serve anything under the specified directory as a  endpoint. Xtype MyApi = "static" :> Raw server :: Server MyApi server = serveDirectory "/var/www" would capture any request to /static/<something> and look for  <something> under /var/www.kIt 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 ( handler in the last position, because servant* will try to match the handlers in order.None      !  !"#$%&'()*+,-./01234BNOPQRSTU`defhijklmnopqrwxyz None'+03457>KLN$Handlers for AuthProtected resources4NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGEaSpecify the type of data returned after we've authenticated a request. quite often this is some User datatype.4NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE4NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGEKnown orphan instance." !"##$%&'()*+,-./0123456789:;<=>?@ABCDEFGHHIJKLMNOPQRSTUVWXYZ[\]^__`abcdefghijklmnopqrstuvwxyz{|}~            !"#$%&'()*+,-./0102030404565758595:5;5<5=5>5?5@5@5A5B5C5DEFGHIJserva_41DS6T4JOWu4WrGIZwBuEoServantServant.Server.Internal.Context"Servant.Server.Internal.ServantErr*Servant.Server.Internal.RoutingApplication!Servant.Server.Internal.BasicAuthServant.Server.Internal.RouterServant.Server.Internal.EnterServant.Server.InternalServant.ServerServant.Utils.StaticFiles Servant.Server.Experimental.AuthControl.Monad.Trans.ReaderReaderTenterserveserveWithContextServant.API.WithNamedContextWithNamedContextbase Data.ProxyProxy NamedContextHasContextEntrygetContextEntryContext EmptyContext:.descendIntoNamedContext$fHasContextEntry:val$fHasContextEntry:val0 $fEqContext $fEqContext0 $fShowContext$fShowContext0 ServantErr errHTTPCodeerrReasonPhraseerrBody errHeadersresponseServantErrerr300err301err302err303err304err305err307err400err401err402err403err404err405err406err407err409err410err411err412err413err414err415err416err417err500err501err502err503err504err505$fExceptionServantErrDelayed capturesDmethodDauthDbodyDserverD RouteResultFail FailFatalRouteRoutingApplication toApplication addCaptureaddMethodCheck addAuthCheck addBodyCheckaddAcceptCheck passToServerbindRouteResultscombineRouteResults runDelayed runAction$fFunctorDelayedBasicAuthCheckunBasicAuthCheckBasicAuthResult Unauthorized BadPassword NoSuchUser AuthorizedmkBAChallengerHdr decodeBAHdr runBasicAuthRouter' WithRequest StaticRouter DynamicRouter LeafRouterChoiceRouter tweakResponsechoice runRouter worseHTTPCode:~>NatunNatEnterliftNat runReaderTNatevalStateTLNatevalStateTSNatlogWriterTSNatlogWriterTLNathoistNatembedNat squashNat generalizeNat $fEnterm:~>n$fCategory(->):~>$fEnter(->)arg(->)$fEnter:<|>arg1:<|>Server HasServerServerTroutecapturedallowedMethodHead allowedMethodprocessMethodRouter methodCheck acceptCheck methodRoutermethodRouterHeaders pathIsEmpty ct_wildcard#$fHasServer*WithNamedContextcontext$fHasServer*:>context$fHasServer*:>context0$fHasServer*:>context1$fHasServer*:>context2$fHasServer*:>context3$fHasServer*:>context4$fHasServer*:>context5$fHasServer*Rawcontext$fHasServer*:>context6$fHasServer*:>context7$fHasServer*:>context8$fHasServer*:>context9$fHasServer*Verbcontext$fHasServer*Verbcontext0$fHasServer*:>context10$fHasServer*:<|>contextserveDirectory AuthHandler unAuthHandlerAuthServerData mkAuthHandlerGHC.Base>>=trans_GZTjP9K5WFq01xC9BAGQpFControl.Monad.Trans.Classlift!Control.Monad.Trans.Writer.StrictWriterTmmorp_2Jm5FlYBlmjDhcU1ovZRKPControl.Monad.Morphhoistembedsquash generalizeserva_0o0b0Dp1pA8GqWnnANRlG9Servant.API.ReqBodyReqBodyServant.API.QueryParam QueryFlagghc-prim GHC.TypesBool QueryParamstext_HmqVQnZSpjaC156ABqPhneData.Text.InternalTexthttpa_3kiLcpdXTUe4CYRpIoinpPWeb.HttpApiData.InternalFromHttpApiData QueryParamMaybeNothingServant.API.HeaderHeaderServant.API.CaptureCaptureServant.API.Alternative:<|>wai_CplzycdRfCIAOASyqIf4ZJ Network.Wai ApplicationServant.API.RawRaw toQueryParamtoHeader toUrlPiece ToHttpApiDataparseQueryParam parseHeader parseUrlPiecehttpt_2kqnYpPBpbH1f4ygoPM6quNetwork.HTTP.Types.MethodPATCHOPTIONSCONNECTTRACEDELETEPUTHEADPOSTGET StdMethodNetwork.HTTP.Types.Version httpMinor httpMajor HttpVersionnetwo_G4AeDaptqixG2pPpsHeFJg Network.URI uriFragmenturiQueryuriPath uriAuthority uriSchemeURIServant.Utils.LinkssafeLinklinkURILinkOrIsElem'IsElemtoLinkMkLinkHasLinkServant.API.Sub:>Servant.API.ResponseHeadersgetHeadersHList getResponseHeadersHConsHNilHListbuildHeadersToBuildHeadersTo getHeaders GetHeaders addHeader AddHeaderUndecodableHeader MissingHeaderServant.API.RemoteHost RemoteHostServant.API.IsSecure NotSecureSecureIsSecureServant.API.VerbsVerbGetPostPutDeletePatch PostCreated GetAccepted PostAcceptedDeleteAccepted PatchAccepted PutAcceptedGetNonAuthoritativePostNonAuthoritativeDeleteNonAuthoritativePatchNonAuthoritativePutNonAuthoritative GetNoContent PostNoContentDeleteNoContentPatchNoContent PutNoContentGetResetContentPostResetContentGetPartialContent reflectMethod ReflectMethodServant.API.BasicAuth BasicAuthbasicAuthPasswordbasicAuthUsername BasicAuthDataServant.API.ContentTypesJSON PlainTextFormUrlEncoded OctetStream contentTypeAccept mimeRender MimeRender mimeUnrender MimeUnrender NoContenttoFormUrlEncodedToFormUrlEncodedfromFormUrlEncodedFromFormUrlEncodedServant.API.Experimental.Auth AuthProtectvault_Ds02DFWDupK8kyaJ6uM5fAData.Vault.LazyVault