yesod-core-1.2.0.4: Creation of type-safe, RESTful web applications.

Safe Haskell | None

Yesod.Core.Handler

Contents

- Handler monad
  - Read information from handler
  - Request information
    - Request datatype
    - Convenience functions
    - Lookup parameters
      - Multi-lookup
- Responses
  - Pure
  - Streaming
  - Redirecting
  - Errors
  - Short-circuit responses.
- Different representations
- Setting headers
  - Content caching and expiration
- Session
  - Ultimate destination
  - Messages
- Helpers for specific content
  - Hamlet
  - Misc
- Lifting
- i18n
- Per-request caching

Synopsis

- data HandlerT site m a
- getYesod :: MonadHandler m => m (HandlerSite m)
- getUrlRender :: MonadHandler m => m (Route (HandlerSite m) -> Text)
- getUrlRenderParams :: MonadHandler m => m (Route (HandlerSite m) -> [(Text, Text)] -> Text)
- getCurrentRoute :: MonadHandler m => m (Maybe (Route (HandlerSite m)))
- getRequest :: MonadHandler m => m YesodRequest
- waiRequest :: MonadHandler m => m Request
- runRequestBody :: MonadHandler m => m RequestBodyContents
- rawRequestBody :: MonadHandler m => Source m ByteString
- type RequestBodyContents = ([(Text, Text)], [(Text, FileInfo)])
- data YesodRequest = YesodRequest {
  - reqGetParams :: ![(Text, Text)]
  - reqCookies :: ![(Text, Text)]
  - reqWaiRequest :: !Request
  - reqLangs :: ![Text]
  - reqToken :: !(Maybe Text)
  - reqSession :: !SessionMap
  - reqAccept :: ![ContentType]
  }
- data FileInfo
- fileName :: FileInfo -> Text
- fileContentType :: FileInfo -> Text
- fileSource :: MonadResource m => FileInfo -> Source m ByteString
- fileMove :: FileInfo -> FilePath -> IO ()
- languages :: MonadHandler m => m [Text]
- lookupGetParam :: MonadHandler m => Text -> m (Maybe Text)
- lookupPostParam :: (MonadResource m, MonadHandler m) => Text -> m (Maybe Text)
- lookupCookie :: MonadHandler m => Text -> m (Maybe Text)
- lookupFile :: (MonadHandler m, MonadResource m) => Text -> m (Maybe FileInfo)
- lookupGetParams :: MonadHandler m => Text -> m [Text]
- lookupPostParams :: (MonadResource m, MonadHandler m) => Text -> m [Text]
- lookupCookies :: MonadHandler m => Text -> m [Text]
- lookupFiles :: (MonadHandler m, MonadResource m) => Text -> m [FileInfo]
- respond :: (Monad m, ToContent a) => ContentType -> a -> m TypedContent
- respondSource :: ContentType -> Source (HandlerT site IO) (Flush Builder) -> HandlerT site IO TypedContent
- sendChunk :: Monad m => ToFlushBuilder a => a -> Producer m (Flush Builder)
- sendFlush :: Monad m => Producer m (Flush Builder)
- sendChunkBS :: Monad m => ByteString -> Producer m (Flush Builder)
- sendChunkLBS :: Monad m => ByteString -> Producer m (Flush Builder)
- sendChunkText :: Monad m => Text -> Producer m (Flush Builder)
- sendChunkLazyText :: Monad m => Text -> Producer m (Flush Builder)
- sendChunkHtml :: Monad m => Html -> Producer m (Flush Builder)
- class RedirectUrl master a where
  - toTextUrl :: (MonadHandler m, HandlerSite m ~ master) => a -> m Text
- redirect :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a
- redirectWith :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => Status -> url -> m a
- redirectToPost :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a
- notFound :: MonadHandler m => m a
- badMethod :: MonadHandler m => m a
- notAuthenticated :: MonadHandler m => m a
- permissionDenied :: MonadHandler m => Text -> m a
- permissionDeniedI :: (RenderMessage (HandlerSite m) msg, MonadHandler m) => msg -> m a
- invalidArgs :: MonadHandler m => [Text] -> m a
- invalidArgsI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => [msg] -> m a
- sendFile :: MonadHandler m => ContentType -> FilePath -> m a
- sendFilePart :: MonadHandler m => ContentType -> FilePath -> Integer -> Integer -> m a
- sendResponse :: (MonadHandler m, ToTypedContent c) => c -> m a
- sendResponseStatus :: (MonadHandler m, ToTypedContent c) => Status -> c -> m a
- sendResponseCreated :: MonadHandler m => Route (HandlerSite m) -> m a
- sendWaiResponse :: MonadHandler m => Response -> m b
- selectRep :: MonadHandler m => Writer (Endo [ProvidedRep m]) () -> m TypedContent
- provideRep :: (Monad m, HasContentType a) => m a -> Writer (Endo [ProvidedRep m]) ()
- provideRepType :: (Monad m, ToContent a) => ContentType -> m a -> Writer (Endo [ProvidedRep m]) ()
- data ProvidedRep m
- setCookie :: MonadHandler m => SetCookie -> m ()
- getExpires :: MonadIO m => Int -> m UTCTime
- deleteCookie :: MonadHandler m => Text -> Text -> m ()
- addHeader :: MonadHandler m => Text -> Text -> m ()
- setHeader :: MonadHandler m => Text -> Text -> m ()
- setLanguage :: MonadHandler m => Text -> m ()
- cacheSeconds :: MonadHandler m => Int -> m ()
- neverExpires :: MonadHandler m => m ()
- alreadyExpired :: MonadHandler m => m ()
- expiresAt :: MonadHandler m => UTCTime -> m ()
- type SessionMap = Map Text ByteString
- lookupSession :: MonadHandler m => Text -> m (Maybe Text)
- lookupSessionBS :: MonadHandler m => Text -> m (Maybe ByteString)
- getSession :: MonadHandler m => m SessionMap
- setSession :: MonadHandler m => Text -> Text -> m ()
- setSessionBS :: MonadHandler m => Text -> ByteString -> m ()
- deleteSession :: MonadHandler m => Text -> m ()
- clearSession :: MonadHandler m => m ()
- setUltDest :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m ()
- setUltDestCurrent :: MonadHandler m => m ()
- setUltDestReferer :: MonadHandler m => m ()
- redirectUltDest :: (RedirectUrl (HandlerSite m) url, MonadHandler m) => url -> m a
- clearUltDest :: MonadHandler m => m ()
- setMessage :: MonadHandler m => Html -> m ()
- setMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => msg -> m ()
- getMessage :: MonadHandler m => m (Maybe Html)
- hamletToRepHtml :: MonadHandler m => HtmlUrl (Route (HandlerSite m)) -> m Html
- giveUrlRenderer :: MonadHandler m => ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output) -> m output
- newIdent :: MonadHandler m => m Text
- handlerToIO :: (MonadIO m1, MonadIO m2) => HandlerT site m1 (HandlerT site IO a -> m2 a)
- getMessageRender :: (MonadHandler m, RenderMessage (HandlerSite m) message) => m (message -> Text)
- cached :: (MonadHandler m, Typeable a) => m a -> m a

# Handler monad

data HandlerT site m a

A generic handler monad, which can have a different subsite and master site. We define a newtype for better error message.

Instances

MonadBaseControl b m => MonadBaseControl b (HandlerT site m)

Note: although we provide a `MonadBaseControl` instance, `lifted-base`'s `fork` function is incompatible with the underlying `ResourceT` system. Instead, if you must fork a separate thread, you should use `resourceForkIO`.

Using fork usually leads to an exception that says "Control.Monad.Trans.Resource.register': The mutable state is being accessed after cleanup. Please contact the maintainers."

MonadBase b m => MonadBase b (HandlerT site m) |
MonadTrans (HandlerT site) |
Monad m => Monad (HandlerT site m) |
Monad m => Functor (HandlerT site m) |
Monad m => Applicative (HandlerT site m) |
MonadThrow m => MonadThrow (HandlerT site m) |
(MonadIO m, MonadUnsafeIO m, MonadThrow m) => MonadResource (HandlerT site m) |
MonadIO m => MonadLogger (HandlerT site m) |
MonadIO m => MonadIO (HandlerT site m) |
MonadResourceBase m => MonadHandler (HandlerT site m) |

## Read information from handler

getYesod :: MonadHandler m => m (HandlerSite m)

Get the master site appliation argument.

getUrlRender :: MonadHandler m => m (Route (HandlerSite m) -> Text)

Get the URL rendering function.

getUrlRenderParams :: MonadHandler m => m (Route (HandlerSite m) -> [(Text, Text)] -> Text)

The URL rendering function with query-string parameters.

getCurrentRoute :: MonadHandler m => m (Maybe (Route (HandlerSite m)))

Get the route requested by the user. If this is a 404 response- where the user requested an invalid route- this function will return `Nothing`.

getRequest :: MonadHandler m => m YesodRequest

waiRequest :: MonadHandler m => m Request

Get the request's `Request` value.

runRequestBody :: MonadHandler m => m RequestBodyContents

rawRequestBody :: MonadHandler m => Source m ByteString

Stream in the raw request body without any parsing.

Since 1.2.0

## Request information

### Request datatype

type RequestBodyContents = ([(Text, Text)], [(Text, FileInfo)])

A tuple containing both the POST parameters and submitted files.

data YesodRequest

The parsed request information. This type augments the standard WAI `Request` with additional information.

Constructors

YesodRequest |

Fields

reqGetParams :: ![(Text, Text)]

  Same as `queryString`, but decoded to `Text`.

reqCookies :: ![(Text, Text)]
reqWaiRequest :: !Request
reqLangs :: ![Text]

  Languages which the client supports. This is an ordered list by preference.

reqToken :: !(Maybe Text)

  A random, session-specific token used to prevent CSRF attacks.

reqSession :: !SessionMap

  Initial session sent from the client.

  Since 1.2.0

reqAccept :: ![ContentType]

  An ordered list of the accepted content types.

  Since 1.2.0

data FileInfo

fileName :: FileInfo -> Text

fileContentType :: FileInfo -> Text

fileSource :: MonadResource m => FileInfo -> Source m ByteString

Stream the data from the file. Since Yesod 1.2, this has been generalized to work in any `MonadResource`.

fileMove :: FileInfo -> FilePath -> IO ()

### Convenience functions

languages :: MonadHandler m => m [Text]

Get the list of supported languages supplied by the user.

Languages are determined based on the following three (in descending order of preference):

- The _LANG get parameter.
- The _LANG cookie.
- The _LANG user session variable.
- Accept-Language HTTP header.

Yesod will seek the first language from the returned list matched with languages supporting by your application. This language will be used to render i18n templates. If a matching language is not found the default language will be used.

This is handled by parseWaiRequest (not exposed).

### Lookup parameters

lookupGetParam :: MonadHandler m => Text -> m (Maybe Text)

Lookup for GET parameters.

lookupPostParam :: (MonadResource m, MonadHandler m) => Text -> m (Maybe Text)

lookupCookie :: MonadHandler m => Text -> m (Maybe Text)

Lookup for cookie data.

lookupFile :: (MonadHandler m, MonadResource m) => Text -> m (Maybe FileInfo)

Lookup for POSTed files.

#### Multi-lookup

lookupGetParams :: MonadHandler m => Text -> m [Text]

Lookup for GET parameters.

lookupPostParams :: (MonadResource m, MonadHandler m) => Text -> m [Text]

Lookup for POST parameters.

lookupCookies :: MonadHandler m => Text -> m [Text]

Lookup for cookie data.

lookupFiles :: (MonadHandler m, MonadResource m) => Text -> m [FileInfo]

Lookup for POSTed files.

# Responses

## Pure

respond :: (Monad m, ToContent a) => ContentType -> a -> m TypedContent

Provide a pure value for the response body.

     respond ct = return . TypedContent ct . toContent

Since 1.2.0

## Streaming

respondSource :: ContentType -> Source (HandlerT site IO) (Flush Builder) -> HandlerT site IO TypedContent

Use a `Source` for the response body.

Note that, for ease of use, the underlying monad is a `HandlerT`. This implies that you can run any `HandlerT` action. However, since a streaming response occurs after the response headers have already been sent, some actions make no sense here. For example: short-circuit responses, setting headers, changing status codes, etc.

Since 1.2.0

sendChunk :: Monad m => ToFlushBuilder a => a -> Producer m (Flush Builder)

In a streaming response, send a single chunk of data. This function works on most datatypes, such as `ByteString` and `Html`.

Since 1.2.0

sendFlush :: Monad m => Producer m (Flush Builder)

In a streaming response, send a flush command, causing all buffered data to be immediately sent to the client.

Since 1.2.0

sendChunkBS :: Monad m => ByteString -> Producer m (Flush Builder)

Type-specialized version of `sendChunk` for strict `ByteString`s.

Since 1.2.0

sendChunkLBS :: Monad m => ByteString -> Producer m (Flush Builder)

Type-specialized version of `sendChunk` for lazy `ByteString`s.

Since 1.2.0

sendChunkText :: Monad m => Text -> Producer m (Flush Builder)

Type-specialized version of `sendChunk` for strict `Text`s.

Since 1.2.0

sendChunkLazyText :: Monad m => Text -> Producer m (Flush Builder)

Type-specialized version of `sendChunk` for lazy `Text`s.

Since 1.2.0

sendChunkHtml :: Monad m => Html -> Producer m (Flush Builder)

Type-specialized version of `sendChunk` for `Html`s.

Since 1.2.0

## Redirecting

class RedirectUrl master a where

Some value which can be turned into a URL for redirects.

Methods

toTextUrl :: (MonadHandler m, HandlerSite m ~ master) => a -> m Text

Converts the value to the URL and a list of query-string parameters.

Instances

RedirectUrl master String |
RedirectUrl master Text |
RedirectUrl master (Route master) |
(~ * key Text, ~ * val Text) => RedirectUrl master (Route master, Map key val) |
(~ * key Text, ~ * val Text) => RedirectUrl master (Route master, [(key, val)]) |

redirect :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a

Redirect to the given route. HTTP status code 303 for HTTP 1.1 clients and 302 for HTTP 1.0 This is the appropriate choice for a get-following-post technique, which should be the usual use case.

If you want direct control of the final status code, or need a different status code, please use `redirectWith`.

redirectWith :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => Status -> url -> m a

Redirect to the given URL with the specified status code.

redirectToPost :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a

Redirect to a POST resource.

This is not technically a redirect; instead, it returns an HTML page with a POST form, and some Javascript to automatically submit the form. This can be useful when you need to post a plain link somewhere that needs to cause changes on the server.

## Errors

notFound :: MonadHandler m => m a

Return a 404 not found page. Also denotes no handler available.

badMethod :: MonadHandler m => m a

Return a 405 method not supported page.

notAuthenticated :: MonadHandler m => m a

Return a 401 status code

permissionDenied :: MonadHandler m => Text -> m a

Return a 403 permission denied page.

permissionDeniedI :: (RenderMessage (HandlerSite m) msg, MonadHandler m) => msg -> m a

Return a 403 permission denied page.

invalidArgs :: MonadHandler m => [Text] -> m a

Return a 400 invalid arguments page.

invalidArgsI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => [msg] -> m a

Return a 400 invalid arguments page.

## Short-circuit responses.

sendFile :: MonadHandler m => ContentType -> FilePath -> m a

Bypass remaining handler code and output the given file.

For some backends, this is more efficient than reading in the file to memory, since they can optimize file sending via a system call to sendfile.

sendFilePart

Arguments

:: MonadHandler m |
=> ContentType |
-> FilePath |
-> Integer | offset
-> Integer | count
-> m a |

Same as `sendFile`, but only sends part of a file.

sendResponse :: (MonadHandler m, ToTypedContent c) => c -> m a

Bypass remaining handler code and output the given content with a 200 status code.

sendResponseStatus :: (MonadHandler m, ToTypedContent c) => Status -> c -> m a

Bypass remaining handler code and output the given content with the given status code.

sendResponseCreated :: MonadHandler m => Route (HandlerSite m) -> m a

Send a 201 Created response with the given route as the Location response header.

sendWaiResponse :: MonadHandler m => Response -> m b

Send a `Response`. Please note: this function is rarely necessary, and will disregard any changes to response headers and session that you have already specified. This function short-circuits. It should be considered only for very specific needs. If you are not sure if you need it, you don't.

# Different representations

HTTP allows content negotation to determine what representation of data you would like to use. The most common example of this is providing both a user-facing HTML page and an API facing JSON response from the same URL. The means of achieving this is the Accept HTTP header, which provides a list of content types the client will accept, sorted by preference.

By using `selectRep` and `provideRep`, you can provide a number of different representations, e.g.:

     selectRep $ do
       provideRep typeHtml $ produceHtmlOutput
       provideRep typeJson $ produceJsonOutput

The first provided representation will be used if no matches are found.

selectRep :: MonadHandler m => Writer (Endo [ProvidedRep m]) () -> m TypedContent

Select a representation to send to the client based on the representations provided inside this do-block. Should be used together with `provideRep`.

Since 1.2.0

provideRep :: (Monad m, HasContentType a) => m a -> Writer (Endo [ProvidedRep m]) ()

Provide a single representation to be used, based on the request of the client. Should be used together with `selectRep`.

Since 1.2.0

provideRepType :: (Monad m, ToContent a) => ContentType -> m a -> Writer (Endo [ProvidedRep m]) ()

Same as `provideRep`, but instead of determining the content type from the type of the value itself, you provide the content type separately. This can be a convenience instead of creating newtype wrappers for uncommonly used content types.

     provideRepType "application/x-special-format" "This is the content"

Since 1.2.0

data ProvidedRep m

Internal representation of a single provided representation.

Since 1.2.0

# Setting headers

setCookie :: MonadHandler m => SetCookie -> m ()

Set the cookie on the client.

getExpires

Arguments

:: MonadIO m |
=> Int | minutes
-> m UTCTime |

Helper function for setCookieExpires value

deleteCookie

Arguments

:: MonadHandler m |
=> Text | key
-> Text | path
-> m () |

Unset the cookie on the client.

Note: although the value used for key and path is `Text`, you should only use ASCII values to be HTTP compliant.

addHeader :: MonadHandler m => Text -> Text -> m ()

Set an arbitrary response header.

Note that, while the data type used here is `Text`, you must provide only ASCII value to be HTTP compliant.

Since 1.2.0

setHeader :: MonadHandler m => Text -> Text -> m ()

Deprecated: Please use addHeader instead

Deprecated synonym for addHeader.

setLanguage :: MonadHandler m => Text -> m ()

Set the language in the user session. Will show up in `languages` on the next request.

## Content caching and expiration

cacheSeconds :: MonadHandler m => Int -> m ()

Set the Cache-Control header to indicate this response should be cached for the given number of seconds.

neverExpires :: MonadHandler m => m ()

Set the Expires header to some date in 2037. In other words, this content is never (realistically) expired.

alreadyExpired :: MonadHandler m => m ()

Set an Expires header in the past, meaning this content should not be cached.

expiresAt :: MonadHandler m => UTCTime -> m ()

Set an Expires header to the given date.

# Session

type SessionMap = Map Text ByteString

lookupSession :: MonadHandler m => Text -> m (Maybe Text)

Lookup for session data.

lookupSessionBS :: MonadHandler m => Text -> m (Maybe ByteString)

Lookup for session data in binary format.

getSession :: MonadHandler m => m SessionMap

Get all session variables.

setSession

Arguments

:: MonadHandler m |
=> Text | key
-> Text | value
-> m () |

Set a variable in the user's session.

The session is handled by the clientsession package: it sets an encrypted and hashed cookie on the client. This ensures that all data is secure and not tampered with.

setSessionBS :: MonadHandler m => Text -> ByteString -> m ()

Same as `setSession`, but uses binary data for the value.

deleteSession :: MonadHandler m => Text -> m ()

Unsets a session variable. See `setSession`.

clearSession :: MonadHandler m => m ()

Clear all session variables.

Since: 1.0.1

## Ultimate destination

setUltDest :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m ()

Sets the ultimate destination variable to the given route.

An ultimate destination is stored in the user session and can be loaded later by `redirectUltDest`.

setUltDestCurrent :: MonadHandler m => m ()

Same as `setUltDest`, but uses the current page.

If this is a 404 handler, there is no current page, and then this call does nothing.

setUltDestReferer :: MonadHandler m => m ()

Sets the ultimate destination to the referer request header, if present.

This function will not overwrite an existing ultdest.

redirectUltDest

Arguments

:: (RedirectUrl (HandlerSite m) url, MonadHandler m) |
=> url | default destination if nothing in session
-> m a |

Redirect to the ultimate destination in the user's session. Clear the value from the session.

The ultimate destination is set with `setUltDest`.

This function uses `redirect`, and thus will perform a temporary redirect to a GET request.

clearUltDest :: MonadHandler m => m ()

Remove a previously set ultimate destination. See `setUltDest`.

## Messages

setMessage :: MonadHandler m => Html -> m ()

Sets a message in the user's session.

See `getMessage`.

setMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => msg -> m ()

Sets a message in the user's session.

See `getMessage`.

getMessage :: MonadHandler m => m (Maybe Html)

Gets the message in the user's session, if available, and then clears the variable.

See `setMessage`.

# Helpers for specific content

## Hamlet

hamletToRepHtml :: MonadHandler m => HtmlUrl (Route (HandlerSite m)) -> m Html

Wraps the `Content` generated by `hamletToContent` in a `RepHtml`.

giveUrlRenderer :: MonadHandler m => ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output) -> m output

Provide a URL rendering function to the given function and return the result. Useful for processing Shakespearean templates.

Since 1.2.0

## Misc

newIdent :: MonadHandler m => m Text

Get a unique identifier.

# Lifting

handlerToIO :: (MonadIO m1, MonadIO m2) => HandlerT site m1 (HandlerT site IO a -> m2 a)

Returns a function that runs `HandlerT` actions inside `IO`.

Sometimes you want to run an inner `HandlerT` action outside the control flow of an HTTP request (on the outer `HandlerT` action). For example, you may want to spawn a new thread:

     getFooR :: Handler RepHtml
     getFooR = do
       runInnerHandler <- handlerToIO
       liftIO $ forkIO $ runInnerHandler $ do
         Code here runs inside GHandler but on a new thread.
         This is the inner GHandler.
         ...
       Code here runs inside the request's control flow.
       This is the outer GHandler.
       ...

Another use case for this function is creating a stream of server-sent events using `GHandler` actions (see `yesod-eventsource`).

Most of the environment from the outer `GHandler` is preserved on the inner `GHandler`, however:

- The request body is cleared (otherwise it would be very difficult to prevent huge memory leaks).
- The cache is cleared (see `CacheKey`).

Changes to the response made inside the inner `GHandler` are ignored (e.g., session variables, cookies, response headers). This allows the inner `GHandler` to outlive the outer `GHandler` (e.g., on the `forkIO` example above, a response may be sent to the client without killing the new thread).

# i18n

getMessageRender :: (MonadHandler m, RenderMessage (HandlerSite m) message) => m (message -> Text)

# Per-request caching

cached :: (MonadHandler m, Typeable a) => m a -> m a

Use a per-request cache to avoid performing the same action multiple times. Note that values are stored by their type. Therefore, you should use newtype wrappers to distinguish logically different types.

Since 1.2.0