Copyright | (c) Fernando Rincon Martin 2020 |
---|---|
License | Apache-2.0 (see the file LICENSE) |
Maintainer | Fernando Rincon Martin <f.rincon@protonmail.com> |
Stability | alpha |
Safe Haskell | None |
Language | Haskell2010 |
This module provides simple routing functions that works on top of Network.Wai applications.
The basic idea is provides functions that modifies an @Application in order to match certain rules. It is inspired on akka http server DSL.
A simple example of a Json rest api:
restApi :: Application restApi = path "hello" $ method GET $ complete $ responseLBS status200 [(hContentType, "text/html")] "<h1>Hellow World!</h1>"
As the result is a Wai @Application
we can run it directly with warp server:
main :: IO () main = run 8080 restApi
The api is in alpha state, so that the api can change in any new release. It is very welcome suggestions and comments.
Synopsis
- type GenericApplication r = Request -> (r -> IO ResponseReceived) -> IO ResponseReceived
- data Rejection = Rejection {}
- class FromUri a where
- fromText :: Text -> a
- fromByteString :: ByteString -> a
- class HasResponseHeaders a where
- mapResponseHeaders :: (ResponseHeaders -> ResponseHeaders) -> a -> a
- alternatives :: [GenericApplication r] -> GenericApplication r
- handleException :: Exception e => (e -> GenericApplication a) -> GenericApplication a -> GenericApplication a
- withDefaultExceptionHandler :: GenericApplication Response -> GenericApplication Response
- complete :: a -> GenericApplication a
- completeIO :: IO a -> GenericApplication a
- mapResponse :: (a -> b) -> GenericApplication a -> GenericApplication b
- withRequest :: (Request -> GenericApplication a) -> GenericApplication a
- path :: Text -> GenericApplication r -> GenericApplication r
- pathSegment :: Text -> GenericApplication r -> GenericApplication r
- pathVar :: FromUri a => (a -> GenericApplication r) -> GenericApplication r
- pathEnd :: GenericApplication r -> GenericApplication r
- singleParameter :: FromUri a => ByteString -> (a -> GenericApplication b) -> GenericApplication b
- maybeSingleParameter :: FromUri a => ByteString -> (Maybe a -> GenericApplication r) -> GenericApplication r
- method :: StdMethod -> GenericApplication e -> GenericApplication e
- data EntityResponse e
- entity :: EntityResponse e -> e
- data NegotiatedResponse
- mapEntity :: (a -> b) -> EntityResponse a -> EntityResponse b
- withCustomNegotiation :: GenericApplication NegotiatedResponse -> GenericApplication Response
- withCustomNegotiation' :: [ByteString] -> GenericApplication NegotiatedResponse -> GenericApplication Response
- negotiated :: [(ByteString, a -> ByteString)] -> EntityResponse a -> NegotiatedResponse
- requestEntity :: [(ByteString, ByteString -> Either String a)] -> (a -> GenericApplication b) -> GenericApplication b
- ok :: a -> EntityResponse a
- created :: a -> EntityResponse a
- notFound :: a -> EntityResponse a
- badRequest :: a -> EntityResponse a
- entityResponse :: Status -> ResponseHeaders -> a -> EntityResponse a
- withContentNegotiationJson :: ((forall a. ToJSON a => EntityResponse a -> NegotiatedResponse) -> GenericApplication NegotiatedResponse) -> GenericApplication Response
- entityJson :: FromJSON a => (a -> GenericApplication b) -> GenericApplication b
Basic functionality
Basic Types and Classes
type GenericApplication r = Request -> (r -> IO ResponseReceived) -> IO ResponseReceived Source #
Abstraction of Wai @Application
on the type of response
Instances
class FromUri a where Source #
Class of types that can be converted from the uri
fromText :: Text -> a Source #
fromByteString :: ByteString -> a Source #
Instances
FromUri Bool Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Basic fromText :: Text -> Bool Source # fromByteString :: ByteString -> Bool Source # | |
FromUri Int Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Basic fromText :: Text -> Int Source # fromByteString :: ByteString -> Int Source # | |
FromUri Int32 Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Basic fromText :: Text -> Int32 Source # fromByteString :: ByteString -> Int32 Source # | |
FromUri Int64 Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Basic fromText :: Text -> Int64 Source # fromByteString :: ByteString -> Int64 Source # | |
FromUri Text Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Basic fromText :: Text -> Text Source # fromByteString :: ByteString -> Text Source # | |
FromUri Text Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Basic fromText :: Text0 -> Text Source # fromByteString :: ByteString -> Text Source # |
class HasResponseHeaders a where Source #
Class which instaances contains response heaaders
mapResponseHeaders :: (ResponseHeaders -> ResponseHeaders) -> a -> a Source #
Instances
Basic combinators
alternatives :: [GenericApplication r] -> GenericApplication r Source #
Combines multiple generic applications in one This function will try every application for each request, and return the first response that does not fail
In case of rejections (Reection thrown), it will rethrown the first exception with higher priority
Exception handling
handleException :: Exception e => (e -> GenericApplication a) -> GenericApplication a -> GenericApplication a Source #
Capture exceptions and convert to generic applications
withDefaultExceptionHandler :: GenericApplication Response -> GenericApplication Response Source #
By default capture all @Rejection
and convert them in specific responses
the content type returned is 'text/plain" and the body will contain the error message
Complete or reject requests
complete :: a -> GenericApplication a Source #
Ends the request responding with the argument
completeIO :: IO a -> GenericApplication a Source #
Ends the request excuting the provided IO and responding the result of the IO
Response Manipulatins
mapResponse :: (a -> b) -> GenericApplication a -> GenericApplication b Source #
Maps a response type to another response type
Requests functions
withRequest :: (Request -> GenericApplication a) -> GenericApplication a Source #
Pass the request to the provided function
Uri path functions
path :: Text -> GenericApplication r -> GenericApplication r Source #
Match the remaining path
pathSegment :: Text -> GenericApplication r -> GenericApplication r Source #
Match the next path segment and remove from the request
pathVar :: FromUri a => (a -> GenericApplication r) -> GenericApplication r Source #
Use the next path segment as a variable and remove from the request
pathEnd :: GenericApplication r -> GenericApplication r Source #
Match if all the path has been consumed or the remaining is a trailing slash
Query string functions
singleParameter :: FromUri a => ByteString -> (a -> GenericApplication b) -> GenericApplication b Source #
Match single parameter in the query string, fails when the parameter is not found or the query string contains multiple values for the parameter
maybeSingleParameter :: FromUri a => ByteString -> (Maybe a -> GenericApplication r) -> GenericApplication r Source #
Match single parameter in the query string, if multiple values for the same parameter found then fails
Http method
method :: StdMethod -> GenericApplication e -> GenericApplication e Source #
Match with standard http method
Entity based
Entity Based types
data EntityResponse e Source #
Instances
HasResponseHeaders (EntityResponse a) Source # | |
Defined in Network.Wai.Routing.Purescheme.Core.Entity mapResponseHeaders :: (ResponseHeaders -> ResponseHeaders) -> EntityResponse a -> EntityResponse a Source # |
entity :: EntityResponse e -> e Source #
Entity Accessor
data NegotiatedResponse Source #
Instances
HasResponseHeaders NegotiatedResponse Source # | |
Basic entity functions
mapEntity :: (a -> b) -> EntityResponse a -> EntityResponse b Source #
Maps a entity response
withCustomNegotiation :: GenericApplication NegotiatedResponse -> GenericApplication Response Source #
Converts an application of NegotiatedResponse to a normal WAI Application
This will reject the request with not acceptable (406) in case the content negotation fail
Note: This is going to do the content negotiation after the inner application has repond with
a NegotiatedResponse. That means, any IO is performed before the conetent negoatiation happen.
TODO: Find another way to do custom negotiation
Better to use @withCustomNegotiation'
withCustomNegotiation' :: [ByteString] -> GenericApplication NegotiatedResponse -> GenericApplication Response Source #
The same than @withCustomNegotiation
but checking the Accept header before doing any IO
negotiated :: [(ByteString, a -> ByteString)] -> EntityResponse a -> NegotiatedResponse Source #
Converts a entity response to a negotiated entity
requestEntity :: [(ByteString, ByteString -> Either String a)] -> (a -> GenericApplication b) -> GenericApplication b Source #
Reads the entity and pass it to provided function
The map provides the accepted media types with the functions that decodes it
As specified in https://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1 a missing content type header from the request is treated "application/octet-stream"
Note: This will read all the payload in memory and then decode it so it can blow up the memory. Better to have a guard on the size of the request
ok :: a -> EntityResponse a Source #
Creates an entity response with status 200
created :: a -> EntityResponse a Source #
Creates a entity response with status 201
notFound :: a -> EntityResponse a Source #
Creates an entity response with status 404
badRequest :: a -> EntityResponse a Source #
Creates an entity response with status 400
entityResponse :: Status -> ResponseHeaders -> a -> EntityResponse a Source #
Creates a entity response with the provided status and response headers
Json based entity functions
withContentNegotiationJson :: ((forall a. ToJSON a => EntityResponse a -> NegotiatedResponse) -> GenericApplication NegotiatedResponse) -> GenericApplication Response Source #
entityJson :: FromJSON a => (a -> GenericApplication b) -> GenericApplication b Source #