ihp-1.5.0: Haskell Web Framework
Safe HaskellNone
LanguageGHC2021

IHP.RouterSupport

Synopsis

Documentation

class HasPath controller => CanRoute controller where Source #

Minimal complete definition

parseRoute'

Methods

parseRoute' :: Parser controller Source #

parseRouteWithAction :: (controller -> Application) -> Parser Application Source #

Builds a WAI Application parser for this controller.

The default implementation parses the controller action using parseRoute' and applies the given callback. The overlappable AutoRoute instance overrides this to defer query string parsing and method validation to the Application closure.

toControllerRoute :: (?request :: Request, ?respond :: Respond, Controller controller, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => ControllerRoute application Source #

Build a ControllerRoute for this controller.

The default wraps the parser in ControllerRouteParser. The overlappable AutoRoute instance overrides this to use ControllerRouteMap for O(1) HashMap dispatch. This is what parseRoute calls.

Instances

Instances details
(AutoRoute controller, Controller controller) => CanRoute controller Source # 
Instance details

Defined in IHP.RouterSupport

Methods

parseRoute' :: Parser controller Source #

parseRouteWithAction :: (controller -> Application) -> Parser Application Source #

toControllerRoute :: (?request :: Request, ?respond :: Respond, Controller controller, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => ControllerRoute application Source #

class HasPath controller where Source #

Type class for types that can be converted to URL paths.

This is used by IHP's routing system to generate URLs for controller actions.

Example:

>>> pathTo UsersAction
"/Users"
>>> pathTo ShowUserAction { userId = "a32913dd-ef80-4f3e-9a91-7879e17b2ece" }
"/ShowUser?userId=a32913dd-ef80-4f3e-9a91-7879e17b2ece"

Methods

pathTo :: controller -> Text Source #

Instances

Instances details
(Show controller, AutoRoute controller) => HasPath controller Source # 
Instance details

Defined in IHP.RouterSupport

Methods

pathTo :: controller -> Text Source #

class Data controller => AutoRoute controller where Source #

Minimal complete definition

Nothing

Methods

autoRouteWithIdType :: (?request :: Request, ?respond :: Respond, Data idType) => (ByteString -> Maybe idType) -> Parser controller Source #

autoRoute :: Parser controller Source #

applyAction :: Constr -> Query -> Either TypedAutoRouteError controller Source #

Constructs a controller value from a matched constructor and query string.

Uses the same id parser as autoRoute. Override this when you override autoRoute with autoRouteWithIdType to keep them in sync.

This is used by parseRoute to defer query string parsing to the Application closure while keeping path matching in the parser.

Example:

instance AutoRoute MyController where
    autoRoute = autoRouteWithIdType (parseIntegerId @(Id MyModel))
    applyAction = applyConstr (parseIntegerId @(Id MyModel))

allowedMethodsForAction :: ByteString -> [StdMethod] Source #

Specifies the allowed HTTP methods for a given action

The default implementation does a smart guess based on the usual naming conventions for controllers.

Example (for default implementation):

>>> allowedMethodsForAction @ProjectsController "DeleteProjectAction"
[DELETE]
>>> allowedMethodsForAction @ProjectsController "UpdateProjectAction"
[POST, PATCH]
>>> allowedMethodsForAction @ProjectsController "CreateProjectAction"
[POST]
>>> allowedMethodsForAction @ProjectsController "ShowProjectAction"
[GET, HEAD]
>>> allowedMethodsForAction @ProjectsController "HelloAction"
[GET, POST, HEAD]

customRoutes :: Parser controller Source #

Custom route parser for overriding individual action routes.

Use this to provide custom URL patterns for specific actions while keeping the auto-generated routes for all other actions.

The custom routes are tried first, before the auto-generated routes. The auto-generated route for the overridden action still works as a fallback.

Example:

instance AutoRoute PostsController where
    customRoutes = do
        string "/posts/"
        postId <- parseId
        endOfInput
        onlyAllowMethods [GET, HEAD]
        pure ShowPostAction { postId }

customPathTo :: controller -> Maybe Text Source #

Custom path generation for overriding individual action URLs.

Use this together with customRoutes to generate custom URLs for specific actions while keeping the auto-generated URLs for all other actions.

Return Just path for actions with custom URLs, or Nothing to fall back to the auto-generated URL.

Example:

instance AutoRoute PostsController where
    customPathTo ShowPostAction { postId } = Just ("/posts/" <> tshow postId)
    customPathTo _ = Nothing

Instances

Instances details
(TypeError ((('Text "Looks like you forgot to pass a " ':<>: 'ShowType argument) ':<>: 'Text " to this ") ':<>: 'ShowType controller) :: Constraint, Data argument, Data controller, Data (argument -> controller)) => AutoRoute (argument -> controller) Source #

Display a better error when the user missed to pass an argument to an action.

E.g. when you forgot to pass a projectId to the ShowProjectAction:

<a href={ShowProjectAction}>Show project</a>

The correct code would be this:

<a href={ShowProjectAction projectId}>Show project</a>

See https://github.com/digitallyinduced/ihp/issues/840

Instance details

Defined in IHP.RouterSupport

Methods

autoRouteWithIdType :: (?request :: Request, ?respond :: Respond, Data idType) => (ByteString -> Maybe idType) -> Parser (argument -> controller) Source #

autoRoute :: Parser (argument -> controller) Source #

applyAction :: Constr -> Query -> Either TypedAutoRouteError (argument -> controller) Source #

allowedMethodsForAction :: ByteString -> [StdMethod] Source #

customRoutes :: Parser (argument -> controller) Source #

customPathTo :: (argument -> controller) -> Maybe Text Source #

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

get :: (Controller action, InitControllerContext application, ?application :: application, Typeable application, Typeable action) => ByteString -> action -> ControllerRoute application Source #

Routes a given path to an action when requested via GET.

Example:

instance FrontController WebApplication where
    controllers = [
            get "/my-custom-page" NewSessionAction
        ]

The request GET /my-custom-page is now executing NewSessionAction

Also see post.

post :: (Controller action, InitControllerContext application, ?application :: application, Typeable application, Typeable action) => ByteString -> action -> ControllerRoute application Source #

Routes a given path to an action when requested via POST.

Example:

instance FrontController WebApplication where
    controllers = [
            post "/do-something" DoSomethingAction
        ]

The request POST /do-something is now executing DoSomethingAction

Also see get.

startPage :: (Controller action, InitControllerContext application, ?application :: application, Typeable application, Typeable action) => action -> ControllerRoute application Source #

Defines the start page for a router (when / is requested).

withPrefix :: ByteString -> [Parser ByteString b] -> Parser ByteString b Source #

class FrontController application where Source #

Minimal complete definition

controllers

Methods

controllers :: [ControllerRoute application] Source #

router :: [ControllerRoute application] -> Parser Application Source #

defaultRouter :: (?application :: application, ?request :: Request, ?respond :: Respond, FrontController application) => [ControllerRoute application] -> Parser Application Source #

parseRoute :: (?request :: Request, ?respond :: Respond, CanRoute controller, Controller controller, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => ControllerRoute application Source #

Create a route entry for a controller.

Automatically uses the HashMap fast path when AutoRoute is available (via the overlappable CanRoute instance), or falls back to Attoparsec for controllers with custom CanRoute instances.

No user code changes needed — parseRoute @PostsController picks the optimal strategy at compile time.

catchAll :: (Controller action, InitControllerContext application, Typeable action, ?application :: application, Typeable application, Data action) => action -> ControllerRoute application Source #

mountFrontController :: (?request :: Request, ?respond :: Respond, FrontController frontController) => frontController -> ControllerRoute application Source #

createAction :: AutoRoute controller => Maybe controller Source #

Returns the create action for a given controller. Example: `createAction @UsersController == Just CreateUserAction`

updateAction :: AutoRoute controller => Maybe (id -> controller) Source #

Returns the update action when given a controller and id. Example: `updateAction @UsersController == Just (id -> UpdateUserAction id)`

urlTo :: (?context :: context, ConfigProvider context, HasPath action) => action -> Text Source #

Returns the url to a given action.

Uses the baseUrl configured in Config/Config.hs. When no baseUrl is configured in development mode, it will automatically detect the correct baseUrl value.

>>> urlTo UsersAction
"http://localhost:8000/Users"
>>> urlTo ShowUserAction { userId = "a32913dd-ef80-4f3e-9a91-7879e17b2ece" }
"http://localhost:8000/ShowUser?userId=a32913dd-ef80-4f3e-9a91-7879e17b2ece"

parseUUID :: Parser UUID Source #

Parses and returns an UUID

parseId :: forall (table :: Symbol). PrimaryKey table ~ UUID => Parser (Id' table) Source #

Parses an UUID, afterwards wraps it in an Id

parseIntegerId :: Data idType => ByteString -> Maybe idType Source #

remainingText :: Parser Text Source #

Returns all the remaining text until the end of the input

parseText :: Parser Text Source #

Parses until the next /

webSocketApp :: (WSApp webSocketApp, InitControllerContext application, ?application :: application, Typeable application, Typeable webSocketApp) => ControllerRoute application Source #

Routes to a given WebSocket app if the path matches the WebSocket app name

Example:

instance FrontController WebApplication where
    controllers = [
            webSocketApp @AutoRefreshWSApp
        ]

The request /AutoRefreshWSApp will call the AutoRefreshWSApp

webSocketAppWithCustomPath :: (WSApp webSocketApp, InitControllerContext application, ?application :: application, Typeable application, Typeable webSocketApp) => ByteString -> ControllerRoute application Source #

Routes to a given WebSocket app if the path matches

Example:

instance FrontController WebApplication where
    controllers = [
            webSocketAppWithCustomPath @AutoRefreshWSApp "my-ws-app"
        ]

The request /my-ws-app will call the AutoRefreshWSApp

webSocketAppWithHTTPFallback :: (WSApp webSocketApp, InitControllerContext application, ?application :: application, Typeable application, Typeable webSocketApp, Controller webSocketApp) => ControllerRoute application Source #

onlyAllowMethods :: (?request :: Request, ?respond :: Respond) => [StdMethod] -> Parser () Source #

Filter methods when writing a custom routing parser

Example:

instance CanRoute ApiController where
   parseRoute' = do
       string "/api/"
       let
           createRecordAction = do
               onlyAllowMethods [POST]

               table <- parseText
               endOfInput
               pure CreateRecordAction { table }

           updateRecordAction = do
               onlyAllowMethods [PATCH]

               table <- parseText
               string "/"
               id <- parseUUID
               pure UpdateRecordAction { table, id }

createRecordAction <|> updateRecordAction

getMethod :: (?request :: Request, ?respond :: Respond) => Parser StdMethod Source #

Parses the HTTP Method from the request and returns it.

routeParam :: (?request :: Request, ?respond :: Respond, ParamReader paramType) => ByteString -> paramType Source #

Parses and returns an integer parseRational :: (Integral a) => Parser a parseRational = Attoparsec.decimal

Parses a route query parameter

Example:

let showPost = do
    string "/post"
    let postId = routeParam "postId"
    pure ShowPostAction { .. }

Will parse the postId query in `/post?postId=09b545dd-9744-4ef8-87b8-8d227f4faa1e`

withImplicits :: ((?request :: Request, ?respond :: Respond) => Application) -> Application Source #

Binds ?request and ?respond from WAI arguments, then runs the given action.

This avoids repeating let ?request = waiRequest; let ?respond = waiRespond at each call site.

applyConstr :: (Data controller, Data idType) => (ByteString -> Maybe idType) -> Constr -> Query -> Either TypedAutoRouteError controller Source #

Given a constructor and a parsed query string, attempt to construct a value of the constructor's type. For example, given the controller

data MyController = MyAction { textArg :: Text, intArg :: Int }

this function will receive a representation of the MyAction constructor as well as some query string [("textArg", "some text"), ("intArg", "123")].

By iterating through the query and attempting to match the type of each constructor argument with some transformation of the query string, we attempt to call MyAction.

data ControllerRoute application Source #

A controller route entry — either a pre-built HashMap for O(1) dispatch, or a custom Attoparsec parser for dynamic URL patterns.

ControllerRouteMap carries both an auto-route HashMap and a fallback parser for custom routes. ControllerRouteParser wraps standalone parsers like get, post, webSocketApp, startPage, etc.

frontControllerToWAIApp scans all ControllerRouteMap HashMaps directly (no Attoparsec) for O(1) dispatch, and only falls back to Attoparsec for custom/dynamic route parsers.

Constructors

ControllerRouteMap !(HashMap ByteString (application -> Application)) (Parser Application)

Auto-route HashMap + custom routes fallback parser (lazy — only evaluated on HashMap miss)

ControllerRouteParser !(Parser Application)

Custom route parser (for get, post, webSocketApp, startPage, etc.)

findInRouteMaps :: ByteString -> [ControllerRoute application] -> Maybe (application -> Application) Source #

Scan ControllerRouteMap entries for a matching path. Returns as soon as a HashMap contains the path. Skips ControllerRouteParser entries.

buildAutoRouteMap :: (AutoRoute controller, Controller controller, InitControllerContext application, Typeable application, Typeable controller) => HashMap ByteString (application -> Application) Source #

Build a HashMap from full paths (prefix + action name) to Application closures. The Application closures take the application value explicitly and handle query string parsing, method validation, and controller execution. Computed once per (controller, application) type pair (NOINLINE CAF).

Orphan instances

(Show controller, AutoRoute controller) => HasPath controller Source # 
Instance details

Methods

pathTo :: controller -> Text Source #

HasPath action => ConvertibleStrings action AttributeValue Source #

This instances makes it possible to write href={MyAction}/ in HSX

Instance details

Methods

convertString :: action -> AttributeValue Source #