Safe Haskell | Safe-Inferred |
---|---|
Language | GHC2021 |
Module for HTML-based servers
Synopsis
- newtype Server m = Server {}
- class ToText a where
- class ToHtmlResp a where
- toHtmlResp :: a -> Resp
- class FromText a where
- class Monad (ServerMonad a) => ToServer a where
- type ServerMonad a :: Type -> Type
- toServer :: a -> Server (ServerMonad a)
- withServerAction :: Monad m => Server m -> m () -> Server m
- (/.) :: ToServer a => Text -> a -> Server (ServerMonad a)
- newtype Capture a = Capture a
- newtype Query (sym :: Symbol) a = Query a
- newtype Optional (sym :: Symbol) a = Optional (Maybe a)
- newtype Body a = Body a
- newtype RawBody = RawBody ByteString
- newtype Header (sym :: Symbol) a = Header (Maybe a)
- newtype FormBody a = FormBody a
- newtype PathInfo = PathInfo [Text]
- data AddHeaders a = AddHeaders {
- headers :: ResponseHeaders
- content :: a
- data SetStatus a = SetStatus {}
- setStatus :: Monad m => Status -> Server m -> Server m
- addHeaders :: Monad m => ResponseHeaders -> Server m -> Server m
- data Error a = Error {}
- handleError :: (Exception a, MonadCatch m) => (a -> Server m) -> Server m -> Server m
- class Monad m => HasServer m where
- type ServerResult m :: Type
- renderServer :: Server m -> ServerResult m
- fromReader :: env -> Server (ReaderT env IO) -> IO (Server IO)
- data ServerConfig = ServerConfig {}
- toApplication :: ServerConfig -> Server IO -> Application
- runServer :: Int -> Server IO -> IO ()
- badRequest :: Text -> Resp
- module Web.FormUrlEncoded
- module Web.HttpApiData
- module Network.HTTP.Types.Status
types
Server type. It is a function fron request to response. Some servers does not return valid value. We use it to find right path.
Example:
server :: Server IO server = "api" /. "v1" /. mconcat [ "foo" /. (\(Query @"name" arg) -> Get @Json (handleFoo arg) , "bar" /. Post @Json handleBar ] handleFoo :: Int -> IO Text handleBar :: IO Text
Note that server is monoid and it can be constructed with Monoid functions and
path constructor (/.)
. To pass inputs for handler we can use special newtype wrappers:
Query
- for required query parametersOptional
- for optional query parametersCapture
- for parsing elements of URIBody
- fot JSON-body inputRawBody
- for raw ByteString inputHeader
- for headers
To distinguish by HTTP-method we use corresponding constructors: Get, Post, Put, etc. Let's discuss the structure of the constructor. Let's take Get for example:
newtype Get ty m a = Get (m a)
Let's look at the arguments of he type
ty
- type of the response. it can be: Text, Html, Json, ByteStringm
- underlying server monada
- result type. It should be convertible to the type of the response.
also result can be wrapped to special data types to modify Http-response. we have wrappers:
SetStatus
- to set statusAddHeaders
- to append headersEither (Error err)
- to response with errors
DSL
Values convertible to lazy text
class ToHtmlResp a where Source #
Values convertible to Html
toHtmlResp :: a -> Resp Source #
Instances
ToMarkup a => ToHtmlResp a Source # | |
Defined in Mig toHtmlResp :: a -> Resp Source # | |
ToHtmlResp a => ToHtmlResp (AddHeaders a) Source # | |
Defined in Mig toHtmlResp :: AddHeaders a -> Resp Source # | |
ToHtmlResp a => ToHtmlResp (SetStatus a) Source # | |
(ToJSON err, ToHtmlResp a) => ToHtmlResp (Either (Error err) a) Source # | |
class FromText a where Source #
Aything convertible from text
class Monad (ServerMonad a) => ToServer a where Source #
Class ToServer contains anything convertible to Server m
. We use it for flexuble composition
of servers from functions with arbitrary number of arguments. Arguments can
be of specific types: Query, Body, Optional, Capture, Header, etc.
We use type-level strings to encode query-names.
Example:
"api" /. "foo" /. (\(Query @"argA" argA) (Optional @"argB" argB) (Body jsonRequest) -> Post @Json $ handleFoo argA argB jsonRequest) handleFoo :: Int -> Maybe Text -> FooRequest -> IO FooResponse handleFoo = ...
Note that we can use any amount of arguments. And type of the input is decoded fron newtype wrapper which is used with argument of the handler function.
Also we can return pure errors with Either. Anything which can be returned from function
can be wrapped to Either (Error err)
.
For example in previous case we can use function which returns errors as values:
type ServerError = Error Text handleFoo :: Int -> Maybe Text -> FooRequest -> IO (Either ServerError FooResponse) handleFoo = ...
the result of error response is automatically matched with normal response of the server and standard Error type lets us pass status to response and some details.
type ServerMonad a :: Type -> Type Source #
toServer :: a -> Server (ServerMonad a) Source #
Instances
path and query
(/.) :: ToServer a => Text -> a -> Server (ServerMonad a) infixr 4 Source #
Path constructor (right associative). Example:
server :: Server IO server = "api" /. "v1" /. mconcat [ "foo" /. Get @Json handleFoo , "bar" /. Post @Json handleBar ] handleFoo, handleBar :: IO Text
Capture
Capture a |
newtype Query (sym :: Symbol) a Source #
Mandatary query parameter. Name is encoded as type-level string. Example:
"api" /. handleFoo handleFoo :: Query "name" Int -> Server IO handleFoo (Query arg) = ...
Query a |
Instances
(FromHttpApiData a, ToServer b, KnownSymbol sym) => ToServer (Query sym a -> b) Source # | |
type ServerMonad (Query sym a -> b) Source # | |
Defined in Mig |
newtype Optional (sym :: Symbol) a Source #
Optional query parameter. Name is encoded as type-level string. Example:
"api" /. handleFoo handleFoo :: Optional "name" -> Server IO handleFoo (Optional maybeArg) = ...
Instances
(FromHttpApiData a, ToServer b, KnownSymbol sym) => ToServer (Optional sym a -> b) Source # | |
type ServerMonad (Optional sym a -> b) Source # | |
Defined in Mig |
Reads Json body (lazy). We can limit the body size with server config. Example:
"api" /. "search" /. (\(Body request) -> handleSearch request)
Body a |
Reads raw body as lazy bytestring. We can limit the body size with server config. Example:
"api" /. "upload" /. (\(RawBody content) -> handleUpload content)
newtype Header (sym :: Symbol) a Source #
Reads input header. Example:
"api" /. (\(Header @"Trace-Id" traceId) -> Post @Json (handleFoo traceId)) handleFoo :: Maybe ByteString -> IO FooResponse
Instances
(FromHttpApiData a, ToServer b, KnownSymbol sym) => ToServer (Header sym a -> b) Source # | |
type ServerMonad (Header sym a -> b) Source # | |
Defined in Mig |
Reads the URL encoded Form input
FormBody a |
Reads current path info
response
data AddHeaders a Source #
Attach headers to response. It can be used inside any ToXxxResp value. Example:
"api" /. handleFoo handleFoo :: Get Text IO (AddHeaders Text) handleFoo = Get $ pure $ AddHeaders headers "Hello foo"
AddHeaders | |
|
Instances
ToHtmlResp a => ToHtmlResp (AddHeaders a) Source # | |
Defined in Mig toHtmlResp :: AddHeaders a -> Resp Source # | |
ToJsonResp a => ToJsonResp (AddHeaders a) Source # | |
Defined in Mig toJsonResp :: AddHeaders a -> Resp Source # | |
ToTextResp a => ToTextResp (AddHeaders a) Source # | |
Defined in Mig toTextResp :: AddHeaders a -> Resp Source # |
Set status to response. It can be ised inside any ToXxxResp value. Example:
"api" /. handleFoo handleFoo :: Get Text IO (SetStatus Text) handleFoo = Get $ pure $ SetStatus status500 "Bad request"
Instances
ToHtmlResp a => ToHtmlResp (SetStatus a) Source # | |
ToJsonResp a => ToJsonResp (SetStatus a) Source # | |
ToTextResp a => ToTextResp (SetStatus a) Source # | |
setStatus :: Monad m => Status -> Server m -> Server m Source #
Sets status for response of the server
addHeaders :: Monad m => ResponseHeaders -> Server m -> Server m Source #
Adds headers for response of the server
Errors
Errors
Instances
(Typeable a, Show a) => Exception (Error a) Source # | |
Defined in Mig.Internal.Types toException :: Error a -> SomeException # fromException :: SomeException -> Maybe (Error a) # displayException :: Error a -> String # | |
Show a => Show (Error a) Source # | |
(Show a, Typeable a) => HasServer (ReaderT env (ExceptT (Error a) IO)) Source # | |
(ToJSON err, ToHtmlResp a) => ToHtmlResp (Either (Error err) a) Source # | |
(ToJSON err, ToJsonResp a) => ToJsonResp (Either (Error err) a) Source # | |
(ToText err, ToTextResp a) => ToTextResp (Either (Error err) a) Source # | |
type ServerResult (ReaderT env (ExceptT (Error a) IO)) Source # | |
handleError :: (Exception a, MonadCatch m) => (a -> Server m) -> Server m -> Server m Source #
Handle errors
Render
class Monad m => HasServer m where Source #
Class contains types which can be converted to IO-based server to run as with WAI-interface.
We can run plain IO-servers and ReaderT over IO based servers. Readers can be wrapped in newtypes.
In that case we can derive automatically HasServer
instance.
type ServerResult m :: Type Source #
renderServer :: Server m -> ServerResult m Source #
fromReader :: env -> Server (ReaderT env IO) -> IO (Server IO) Source #
Render reader server to IO-based server
Run
toApplication :: ServerConfig -> Server IO -> Application Source #
Convert server to WAI-application
utils
badRequest :: Text -> Resp Source #
Bad request response
module Web.FormUrlEncoded
module Web.HttpApiData
module Network.HTTP.Types.Status