| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
IHP.RouterSupport
Contents
Synopsis
- class HasPath controller => CanRoute controller where
- parseRoute' :: Parser controller
- parseRouteWithAction :: (controller -> Application) -> Parser Application
- toControllerRoute :: (?request :: Request, ?respond :: Respond, Controller controller, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => ControllerRoute application
- class HasPath controller where
- class Data controller => AutoRoute controller where
- autoRouteWithIdType :: (?request :: Request, ?respond :: Respond, Data idType) => (ByteString -> Maybe idType) -> Parser controller
- autoRoute :: Parser controller
- applyAction :: Constr -> Query -> Either TypedAutoRouteError controller
- allowedMethodsForAction :: ByteString -> [StdMethod]
- customRoutes :: Parser controller
- customPathTo :: controller -> Maybe Text
- runAction :: (Controller controller, ?context :: ControllerContext, ?modelContext :: ModelContext, ?respond :: Respond) => controller -> IO ResponseReceived
- get :: (Controller action, InitControllerContext application, ?application :: application, Typeable application, Typeable action) => ByteString -> action -> ControllerRoute application
- post :: (Controller action, InitControllerContext application, ?application :: application, Typeable application, Typeable action) => ByteString -> action -> ControllerRoute application
- startPage :: (Controller action, InitControllerContext application, ?application :: application, Typeable application, Typeable action) => action -> ControllerRoute application
- frontControllerToWAIApp :: (FrontController app, WSApp autoRefreshApp, Typeable autoRefreshApp, InitControllerContext ()) => Middleware -> app -> Application -> Application
- withPrefix :: ByteString -> [Parser ByteString b] -> Parser ByteString b
- class FrontController application where
- controllers :: [ControllerRoute application]
- router :: [ControllerRoute application] -> Parser Application
- defaultRouter :: (?application :: application, ?request :: Request, ?respond :: Respond, FrontController application) => [ControllerRoute application] -> Parser Application
- parseRoute :: (?request :: Request, ?respond :: Respond, CanRoute controller, Controller controller, InitControllerContext application, ?application :: application, Typeable application, Typeable controller) => ControllerRoute application
- catchAll :: (Controller action, InitControllerContext application, Typeable action, ?application :: application, Typeable application, Data action) => action -> ControllerRoute application
- mountFrontController :: (?request :: Request, ?respond :: Respond, FrontController frontController) => frontController -> ControllerRoute application
- createAction :: AutoRoute controller => Maybe controller
- updateAction :: AutoRoute controller => Maybe (id -> controller)
- urlTo :: (?context :: context, ConfigProvider context, HasPath action) => action -> Text
- parseUUID :: Parser UUID
- parseId :: forall (table :: Symbol). PrimaryKey table ~ UUID => Parser (Id' table)
- parseIntegerId :: Data idType => ByteString -> Maybe idType
- remainingText :: Parser Text
- parseText :: Parser Text
- webSocketApp :: (WSApp webSocketApp, InitControllerContext application, ?application :: application, Typeable application, Typeable webSocketApp) => ControllerRoute application
- webSocketAppWithCustomPath :: (WSApp webSocketApp, InitControllerContext application, ?application :: application, Typeable application, Typeable webSocketApp) => ByteString -> ControllerRoute application
- webSocketAppWithHTTPFallback :: (WSApp webSocketApp, InitControllerContext application, ?application :: application, Typeable application, Typeable webSocketApp, Controller webSocketApp) => ControllerRoute application
- onlyAllowMethods :: (?request :: Request, ?respond :: Respond) => [StdMethod] -> Parser ()
- getMethod :: (?request :: Request, ?respond :: Respond) => Parser StdMethod
- routeParam :: (?request :: Request, ?respond :: Respond, ParamReader paramType) => ByteString -> paramType
- withImplicits :: ((?request :: Request, ?respond :: Respond) => Application) -> Application
- applyConstr :: (Data controller, Data idType) => (ByteString -> Maybe idType) -> Constr -> Query -> Either TypedAutoRouteError controller
- data ControllerRoute application
- = ControllerRouteMap !(HashMap ByteString (application -> Application)) (Parser Application)
- | ControllerRouteParser !(Parser Application)
- findInRouteMaps :: ByteString -> [ControllerRoute application] -> Maybe (application -> Application)
- buildAutoRouteMap :: (AutoRoute controller, Controller controller, InitControllerContext application, Typeable application, Typeable controller) => HashMap ByteString (application -> Application)
Documentation
class HasPath controller => CanRoute controller where Source #
Minimal complete definition
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
| (AutoRoute controller, Controller controller) => CanRoute controller Source # | |
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"
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 _ = NothingInstances
| (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> |
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).
frontControllerToWAIApp :: (FrontController app, WSApp autoRefreshApp, Typeable autoRefreshApp, InitControllerContext ()) => Middleware -> app -> Application -> Application Source #
withPrefix :: ByteString -> [Parser ByteString b] -> Parser ByteString b Source #
class FrontController application where Source #
Minimal complete definition
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"
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
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 <|> updateRecordActiongetMethod :: (?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 # | |
| HasPath action => ConvertibleStrings action AttributeValue Source # | This instances makes it possible to write |
Methods convertString :: action -> AttributeValue Source # | |