ihp-1.5.0: Haskell Web Framework
Safe HaskellNone
LanguageGHC2021

IHP.ControllerSupport

Synopsis

Documentation

(|>) :: a -> (a -> b) -> b infixl 8 Source #

Pipe operator

getRequestPath :: (?request :: Request) => ByteString Source #

Returns the request path, e.g. /Users or /CreateUser

getRequestPathAndQuery :: (?request :: Request) => ByteString Source #

Returns the request path and the query params, e.g. /ShowUser?userId=9bd6b37b-2e53-40a4-bb7b-fdba67d6af42

getHeader :: (?request :: Request) => ByteString -> Maybe ByteString Source #

Returns a header value for a given header name. Returns Nothing if not found

The header is looked up in a case insensitive way.

>>> getHeader "Content-Type"
Just "text/html"
>>> getHeader "X-My-Custom-Header"
Nothing

requestHeaders :: Request -> RequestHeaders Source #

A list of headers (a pair of key and value) in an HTTP request.

getFiles :: (?request :: Request) => [File ByteString] Source #

class (Show controller, Eq controller) => Controller controller where Source #

Minimal complete definition

action

Methods

beforeAction :: IO () Source #

action :: controller -> IO ResponseReceived Source #

runAction :: (Controller controller, ?context :: ControllerContext, ?modelContext :: ModelContext, ?respond :: Respond) => controller -> IO ResponseReceived Source #

data ControllerContext Source #

A container storing useful data along the request lifecycle, such as the request, the current user, set current view layout, flash messages, ...

The controller context is usually accessed via the ?context variable. It's available inside the action and the view. Think of it as a key-value-map where the key is the type of the value.

You can store information inside the context using putContext:

>>> newtype CurrentLayout = CurrentLayout Html
>>> 
>>> ?context <- newControllerContext
>>> putContext (CurrentLayout layout)

Inside an action you can access the values using fromContext:

>>> (CurrentLayout layout) <- fromContext

You can freeze the context and then access values without being inside an IO context (like inside views which are pure):

Call freeze inside an IO part:

>>> ?context <- freeze ?context

(freeze is automatically called by IHP before rendering a view, so usually you don't need to call it manually)

Then use the frozen context from your pure code like this:

>>> let (CurrentLayout layout) = fromFrozenContext in ...

The context is initially created before a action is going to be executed. Its life cycle looks like this:

  • newControllerContext: The new controller context is created
  • The runActionWithNewContext fills in a few default values: The current ?application and also the Flash Messages to be rendered in the to-be-generated response.
  • initContext: The initContext function of the InitControllerContext WebApplication (inside your FrontController.hs) is called. There application-specific context can be provided. Usually this is the current user and the default layout.
  • beforeAction: Here the context could also be modified. E.g. the layout could be overriden here for the whole controller.
  • action ..: The action itself.
  • Freezing: Before rendering the response, the container is frozen. Frozen means that all previously mutable fields become immutable.
  • View Rendering: The frozen container is now used inside the view and layout to display information such as the current user or flash messages

Instances

Instances details
HasField "frameworkConfig" ControllerContext FrameworkConfig Source #

Access frameworkConfig via the request vault

Instance details

Defined in IHP.Controller.Context

HasField "logger" ControllerContext Logger Source #

Access logger from the request vault

Instance details

Defined in IHP.Controller.Context

HasField "request" ControllerContext Request Source #

Access request from the TMap

This allows controllerContext.request to work by retrieving the WAI Request stored in the TMap.

Instance details

Defined in IHP.Controller.Context

class InitControllerContext (application :: k) where Source #

Minimal complete definition

Nothing

Methods

initContext :: IO () Source #

Instances

Instances details
InitControllerContext () Source # 
Instance details

Defined in IHP.ControllerSupport

Methods

initContext :: IO () Source #

runActionWithNewContext :: forall application controller. (Controller controller, ?request :: Request, ?respond :: Respond, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => controller -> IO ResponseReceived Source #

newContextForAction :: forall application controller. (Controller controller, ?request :: Request, ?respond :: Respond, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => controller -> IO ControllerContext Source #

respondWith :: (?request :: Request, ?respond :: Respond) => Response -> IO ResponseReceived Source #

Sends a response to the client. Used by render functions.

This is the normal way to respond - it calls the WAI respond callback directly and returns the ResponseReceived.

respondAndExit :: (?request :: Request, ?respond :: Respond) => Response -> IO a Source #

Sends a response and exits the current action via early return. Sends the response via respondWith then throws EarlyReturnException so the action short-circuits.

earlyReturn :: IO ResponseReceived -> IO a Source #

Exit a request handler early after sending a response.

Use this when you want to conditionally exit a handler:

handler = do
    when someCondition do
        earlyReturn (sendErrorResponse ...)
    -- rest of the handler
    sendNormalResponse

The function runs the given IO action (which should send a response), then throws EarlyReturnException to exit. The middleware catches this exception so it doesn't propagate further.

jumpToAction :: (Controller action, ?context :: ControllerContext, ?modelContext :: ModelContext, ?respond :: Respond, ?request :: Request) => action -> IO ResponseReceived Source #

requestBodyJSON :: (?request :: Request, ?respond :: Respond) => IO Value Source #

startWebSocketApp :: forall webSocketApp application. (?request :: Request, ?respond :: Respond, InitControllerContext application, ?application :: application, Typeable application, WSApp webSocketApp) => webSocketApp -> IO ResponseReceived -> Application Source #

startWebSocketAppAndFailOnHTTP :: forall webSocketApp application. (?request :: Request, ?respond :: Respond, InitControllerContext application, ?application :: application, Typeable application, WSApp webSocketApp) => webSocketApp -> Application Source #

setHeader :: (?request :: Request) => Header -> IO () Source #

Set a header value for a given header name.

>>> setHeader ("Content-Language", "en")

getAppConfig :: forall configParameter context. (?context :: context, ConfigProvider context, Typeable configParameter) => configParameter Source #

Returns a custom config parameter

>>> getAppConfig @StripePublicKey
StripePublicKey "pk_test_..."

Example:

First you need to define a custom config parameter in Config.hs:

-- Config/Config.hs
newtype StripePublicKey = StripePublicKey Text

config :: ConfigBuilder
config = do
    -- ...
    stripePublicKey <- StripePublicKey <$> env @Text "STRIPE_PUBLIC_KEY"
    option stripePublicKey

Then you can access it using getAppConfig:

action MyAction = do
    let (StripePublicKey stripePublicKey) = getAppConfig @StripePublicKey

    putStrLn ("Stripe public key: " <> stripePublicKey)

type Respond = Response -> IO ResponseReceived Source #

Type alias for WAI respond function

data Request Source #

Information on the request sent by the client. This abstracts away the details of the underlying implementation.

Instances

Instances details
Show Request 
Instance details

Defined in Network.Wai.Internal

ToApplication Application 
Instance details

Defined in Network.Wai.UrlMap

ToApplication UrlMap 
Instance details

Defined in Network.Wai.UrlMap

HasField "actionType" Request ActionType Source # 
Instance details

Defined in IHP.ActionType

HasField "frameworkConfig" Request FrameworkConfig Source # 
Instance details

Defined in IHP.RequestVault

HasField "logger" Request Logger Source # 
Instance details

Defined in IHP.RequestVault

Methods

getField :: Request -> Logger #

HasField "modelContext" Request ModelContext Source # 
Instance details

Defined in IHP.RequestVault.ModelContext

HasField "parsedBody" Request RequestBody Source # 
Instance details

Defined in IHP.RequestVault.ModelContext

HasField "pgListener" Request PGListener Source # 
Instance details

Defined in IHP.RequestVault

HasField "request" ControllerContext Request Source #

Access request from the TMap

This allows controllerContext.request to work by retrieving the WAI Request stored in the TMap.

Instance details

Defined in IHP.Controller.Context

setupActionContext :: (InitControllerContext application, ?application :: application, Typeable application) => TypeRep -> Request -> Respond -> IO ControllerContext Source #

Shared request context setup, specialized once per application type. Takes a pre-computed TypeRep to avoid per-controller-type code duplication. NOINLINE ensures GHC compiles one copy shared across all controllers.

Exceptions from initContext (including EarlyReturnException) propagate to the caller, which is expected to catch them.

data ResponseReceived Source #

A special datatype to indicate that the WAI handler has received the response. This is to avoid the need for Rank2Types in the definition of Application.

It is highly advised that only WAI handlers import and use the data constructor for this data type.

Since: wai-3.0.0

Instances

Instances details
ToApplication Application 
Instance details

Defined in Network.Wai.UrlMap

ToApplication UrlMap 
Instance details

Defined in Network.Wai.UrlMap