Safe Haskell | None |
---|---|
Language | Haskell2010 |
A Haskell web framework inspired by the Scotty framework, with an eye towards performance, extensibility, and ease of use.
module Main where import Data.Monoid ((<>)) import Web.Growler main = growl id defaultConfig $ do get "/" $ text "Hello, World!" get "/:name" $ do name <- param "name" text ("Hello, " <> name <> "!")
- growl :: MonadIO m => (forall a. m a -> IO a) -> GrowlerConfig m -> GrowlerT m () -> IO ()
- growler :: MonadIO m => (forall a. m a -> IO a) -> GrowlerConfig m -> GrowlerT m () -> IO Application
- defaultConfig :: MonadIO m => GrowlerConfig m
- data GrowlerConfig m = GrowlerConfig {
- growlerConfigNotFoundHandler :: HandlerT m ()
- growlerConfigErrorHandler :: SomeException -> HandlerT m ()
- type Growler = GrowlerT IO
- data GrowlerT m a
- regex :: String -> RoutePattern
- capture :: String -> RoutePattern
- function :: (Request -> Text) -> (Request -> MatchResult) -> RoutePattern
- literal :: String -> RoutePattern
- mount :: Monad m => RoutePattern -> GrowlerT m () -> GrowlerT m ()
- handlerHook :: Monad m => (HandlerT m () -> HandlerT m ()) -> GrowlerT m ()
- notFound :: Monad m => HandlerT m ()
- get :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m ()
- post :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m ()
- put :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m ()
- delete :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m ()
- patch :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m ()
- matchAny :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m ()
- addRoute :: MonadIO m => StdMethod -> RoutePattern -> HandlerT m () -> GrowlerT m ()
- type Handler = HandlerT IO
- data HandlerT m a
- request :: Monad m => HandlerT m Request
- routePattern :: Monad m => HandlerT m (Maybe Text)
- params :: Monad m => HandlerT m [Param]
- file :: Monad m => FilePath -> Maybe FilePart -> HandlerT m ()
- builder :: Monad m => Builder -> HandlerT m ()
- bytestring :: Monad m => ByteString -> HandlerT m ()
- stream :: Monad m => StreamingBody -> HandlerT m ()
- raw :: MonadIO m => (IO ByteString -> (ByteString -> IO ()) -> IO ()) -> Response -> HandlerT m ()
- currentResponse :: Monad m => HandlerT m ResponseState
- abort :: Monad m => ResponseState -> HandlerT m ()
- lookupParam :: (Functor m, Monad m, Parsable a) => ByteString -> HandlerT m (Maybe a)
- param :: (Functor m, Monad m, Parsable a) => ByteString -> HandlerT m a
- formData :: MonadIO m => BackEnd y -> HandlerT m ([(ByteString, ByteString)], [File y])
- headers :: Monad m => HandlerT m RequestHeaders
- jsonData :: (FromJSON a, MonadIO m) => HandlerT m (Either JsonInputError a)
- status :: Monad m => Status -> HandlerT m ()
- addHeader :: Monad m => CI ByteString -> ByteString -> HandlerT m ()
- setHeader :: Monad m => CI ByteString -> ByteString -> HandlerT m ()
- raise :: Monad m => ByteString -> HandlerT m ()
- redirect :: Monad m => Text -> HandlerT m ()
- text :: Monad m => Text -> HandlerT m ()
- html :: Monad m => Text -> HandlerT m ()
- json :: Monad m => ToJSON a => a -> HandlerT m ()
- data JsonInputError
- data DecodingError :: *
- class Parsable a where
- parseParam :: ByteString -> Either ByteString a
- parseParamList :: ByteString -> Either ByteString [a]
- readEither :: Read a => ByteString -> Either ByteString a
- body :: Monad m => BodySource -> HandlerT m ()
- data BodySource
- = FileSource !FilePath !(Maybe FilePart)
- | BuilderSource !Builder
- | LBSSource !ByteString
- | StreamSource !StreamingBody
- | RawSource !(IO ByteString -> (ByteString -> IO ()) -> IO ()) !Response
- data ResponseState = ResponseState {}
- newtype RoutePattern = RoutePattern {}
Running a growler app
:: MonadIO m | |
=> (forall a. m a -> IO a) | A function to convert your base monad of choice into IO. |
-> GrowlerConfig m | |
-> GrowlerT m () | The router for all the other routes |
-> IO () |
The simple approach to starting up a web server
:: MonadIO m | |
=> (forall a. m a -> IO a) | A function to convert your base monad of choice into IO. |
-> GrowlerConfig m | |
-> GrowlerT m () | The router for all the other routes |
-> IO Application |
For more complex needs, access to the actual WAI Application
. Useful for adding middleware.
defaultConfig :: MonadIO m => GrowlerConfig m Source
data GrowlerConfig m Source
GrowlerConfig | |
|
Routing
regex :: String -> RoutePattern Source
Match requests using a regular expression. Named captures are not yet supported.
get (regex "^/f(.*)r$") $ do path <- param "0" cap <- param "1" text $ mconcat ["Path: ", path, "\nCapture: ", cap]
>>>
curl http://localhost:3000/foo/bar
Path: /foo/bar Capture: oo/ba
capture :: String -> RoutePattern Source
Standard Sinatra-style route. Named captures are prepended with colons. This is the default route type generated by OverloadedString routes. i.e.
get (capture "/foo/:bar") $ ...
and
{-# LANGUAGE OverloadedStrings #-} ... get "/foo/:bar" $ ...
are equivalent.
function :: (Request -> Text) -> (Request -> MatchResult) -> RoutePattern Source
Build a route based on a function which can match using the entire Request
object.
Nothing
indicates the route does not match. A Just
value indicates
a successful match, optionally returning a list of key-value pairs accessible
by param
.
get (function $ \req -> Just [("version", T.pack $ show $ httpVersion req)]) $ do v <- param "version" text v
>>>
curl http://localhost:3000/
HTTP/1.1
literal :: String -> RoutePattern Source
Build a route that requires the requested path match exactly, without captures.
HTTP Methods
matchAny :: MonadIO m => RoutePattern -> HandlerT m () -> GrowlerT m () Source
Add a route that matches regardless of the HTTP verb.
Primitives
addRoute :: MonadIO m => StdMethod -> RoutePattern -> HandlerT m () -> GrowlerT m () Source
Define a route with a StdMethod
, Text
value representing the path spec,
and a body (Action
) which modifies the response.
addroute GET "/" $ text "beam me up!"
The path spec can include values starting with a colon, which are interpreted
as captures. These are named wildcards that can be looked up with param
.
addroute GET "/foo/:bar" $ do v <- param "bar" text v
>>>
curl http://localhost:3000/foo/something
something
Handlers
MonadTrans HandlerT | |
MonadTransControl HandlerT | |
MonadBase b m => MonadBase b (HandlerT m) | |
MonadBaseControl b m => MonadBaseControl b (HandlerT m) | |
Monad m => Monad (HandlerT m) | |
Monad m => Functor (HandlerT m) | |
Monad m => Applicative (HandlerT m) | |
MonadIO m => MonadIO (HandlerT m) | |
type StT HandlerT a = StHandlerT a | |
type StM (HandlerT m) a = ComposeSt HandlerT m a |
Primitive request functions
routePattern :: Monad m => HandlerT m (Maybe Text) Source
Get the pattern that was matched in the router, e.g. "foo:bar"
Primitive response functions
:: Monad m | |
=> FilePath | The file to send |
-> Maybe FilePart | If |
-> HandlerT m () |
Send a file as the response body.
builder :: Monad m => Builder -> HandlerT m () Source
Set the response body to a ByteString Builder
. Sets no headers.
bytestring :: Monad m => ByteString -> HandlerT m () Source
Set the response body to a lazy ByteString
. Sets no headers.
stream :: Monad m => StreamingBody -> HandlerT m () Source
Send a streaming response body. Sets no headers.
:: MonadIO m | |
=> (IO ByteString -> (ByteString -> IO ()) -> IO ()) | |
-> Response | Backup response when the WAI provider doesn't support upgrading (e.g. CGI) |
-> HandlerT m () |
Send raw output as the response body. Useful for e.g. websockets. See WAI's responseRaw
for more details.
currentResponse :: Monad m => HandlerT m ResponseState Source
abort :: Monad m => ResponseState -> HandlerT m () Source
End the handler early with an arbitrary ResponseState
.
Convenience functions
Request helpers
lookupParam :: (Functor m, Monad m, Parsable a) => ByteString -> HandlerT m (Maybe a) Source
formData :: MonadIO m => BackEnd y -> HandlerT m ([(ByteString, ByteString)], [File y]) Source
Parse out the form parameters and the uploaded files. Consumes the request body.
headers :: Monad m => HandlerT m RequestHeaders Source
Get all the request headers.
jsonData :: (FromJSON a, MonadIO m) => HandlerT m (Either JsonInputError a) Source
Consume the request body as a JSON value. Returns a JsonInputError
on failure.
Response helpers
addHeader :: Monad m => CI ByteString -> ByteString -> HandlerT m () Source
Add a header to the response. Header names are case-insensitive.
setHeader :: Monad m => CI ByteString -> ByteString -> HandlerT m () Source
Set a response header. Overrides duplicate headers of the same name.
raise :: Monad m => ByteString -> HandlerT m () Source
Terminate the current handler and send a 302 Found
redirect to the provided URL.
Other headers that have already been set will also be returned in the request.
text :: Monad m => Text -> HandlerT m () Source
Return plain text as the response body. Sets the Content-Type header to "text/plain; charset=utf-8".
html :: Monad m => Text -> HandlerT m () Source
Return HTML as the response body. Sets the Content-Type header to "text/html; charset=utf-8".
If you're using something like blaze-html or lucid, you'll probably get better performance by rolling
your own function that sets the response body to a Builder
.
json :: Monad m => ToJSON a => a -> HandlerT m () Source
Send a value as JSON as the response body. Also sets the content type to application/json.
data JsonInputError Source
data DecodingError :: *
An error while decoding a JSON value.
AttoparsecError ParsingError | An |
FromJSONError String | An |
Parsable
Minimum implemention: parseParam
parseParam :: ByteString -> Either ByteString a Source
Take a ByteString
value and parse it as a
, or fail with a message.
parseParamList :: ByteString -> Either ByteString [a] Source
Default implementation parses comma-delimited lists.
parseParamList t = mapM parseParam (BS.split ',' t)
Parsable Bool | |
Parsable Char | Overrides default |
Parsable Double | |
Parsable Float | |
Parsable Int | |
Parsable Integer | |
Parsable () | Checks if parameter is present and is null-valued, not a literal '()'.
If the URI requested is: '/foo?bar=()&baz' then |
Parsable ByteString | |
Parsable Text | |
Parsable Text | |
Parsable a => Parsable [a] |
readEither :: Read a => ByteString -> Either ByteString a Source
Internals
body :: Monad m => BodySource -> HandlerT m () Source
Set an arbitrary body source for the response.
data BodySource Source
FileSource !FilePath !(Maybe FilePart) | |
BuilderSource !Builder | |
LBSSource !ByteString | |
StreamSource !StreamingBody | |
RawSource !(IO ByteString -> (ByteString -> IO ()) -> IO ()) !Response |