ihp-router-1.0.0: Trie-based routing with a Yesod-style DSL for WAI
Safe HaskellNone
LanguageGHC2021

IHP.Router.DSL.AST

Description

Pure data types describing a parsed [routes| ... |] block. No Template Haskell — this module is safe to import from both the parser (compile-time textual layer) and the TH splice (compile-time code-generation layer).

The grammar, informally (RFC 6570 URI-template syntax for path parameters):

[routes|ControllerName
GET    /posts                 PostsAction
POST   /posts                 CreatePostAction
GET    /posts/{postId}        ShowPostAction
GET    /posts/{postId}/edit   EditPostAction
PATCH  /posts/{postId}        UpdatePostAction
DELETE /posts/{postId}        DeletePostAction
|]

{name} binds the segment to a record field of the same name on the action constructor. {name:Type} is an explicit-type escape hatch. {+name} (RFC 6570 reserved-string expansion) matches the rest of the path. GET|POST allows multiple methods for one route. Anything after -- on a line is a comment.

Synopsis

Documentation

data Routes Source #

A complete parsed [routes| ... |] block.

  • Single-controller — bare identifier header: 'controllerName' = Just "PostsController"
  • Multi-controller — empty header: 'controllerName' = Nothing. The TH splice reifies each action constructor to find its parent type and emits instances per type.

Constructors

Routes 

Fields

Instances

Instances details
Show Routes Source # 
Instance details

Defined in IHP.Router.DSL.AST

Eq Routes Source # 
Instance details

Defined in IHP.Router.DSL.AST

Methods

(==) :: Routes -> Routes -> Bool #

(/=) :: Routes -> Routes -> Bool #

data Route Source #

A single route: one or more methods, a path pattern, an optional query-param spec, and an action reference.

Constructors

Route 

Fields

  • routeMethods :: ![Method]
     
  • routePath :: ![PathSeg]
     
  • routeQueryParams :: ![Text]

    Query-string parameters declared on the route via the ?name1&name2 suffix. Each name is expected to correspond to a record field of the action constructor (either directly, or via a {field = #name} rebinding in the ActionRef). Empty list means no ? clause was written — all unbound record fields must then be the empty set, or the TH splice errors out.

  • routeAction :: !ActionRef
     
  • routeLine :: !Int
     
  • routeKind :: !RouteKind

    Discriminates HTTP and WebSocket routes. WebSocket routes are written with the WS keyword in place of an HTTP method; the parser stores routeMethods = [GET] for them so they register under the same trie method that carries the WS handshake.

Instances

Instances details
Show Route Source # 
Instance details

Defined in IHP.Router.DSL.AST

Methods

showsPrec :: Int -> Route -> ShowS #

show :: Route -> String #

showList :: [Route] -> ShowS #

Eq Route Source # 
Instance details

Defined in IHP.Router.DSL.AST

Methods

(==) :: Route -> Route -> Bool #

(/=) :: Route -> Route -> Bool #

data RouteKind Source #

Whether a route is an HTTP route or a WebSocket route.

WebSocket routes are written WS /path TypeName; the right-hand identifier is the WSApp-instance type itself (not an action constructor), and the path must be static — no {capture} segments and no ?query list — in this v1.

The generic ihp-router package has no notion of WSApp; it's the IHP-side splice in IHP.Router.IHP that turns WebSocketRoute entries into webSocketRoute calls. The kind tag lives here so both halves of the splice can share parser output.

Constructors

HttpRoute 
WebSocketRoute 

Instances

Instances details
Show RouteKind Source # 
Instance details

Defined in IHP.Router.DSL.AST

Eq RouteKind Source # 
Instance details

Defined in IHP.Router.DSL.AST

data PathSeg Source #

A single segment of a route path.

Constructors

Literal !Text

A literal path piece like "posts" in postsnew.

Capture !Text !(Maybe Text)

{name} or {name:Type} — captures one segment, bound to the action field of the same name. The optional Text is a raw Haskell type expression (escape hatch for when the capture type can't be inferred from the record field alone).

Splat !Text !(Maybe Text)

{+name} or {+name:Type} — RFC 6570 reserved-string form: captures the remainder of the path including any / characters. Default type is Text.

Instances

Instances details
Show PathSeg Source # 
Instance details

Defined in IHP.Router.DSL.AST

Eq PathSeg Source # 
Instance details

Defined in IHP.Router.DSL.AST

Methods

(==) :: PathSeg -> PathSeg -> Bool #

(/=) :: PathSeg -> PathSeg -> Bool #

data ActionRef Source #

Reference to an action constructor, optionally with explicit field-to-capture bindings for when a field name in the constructor differs from the capture name in the path.

Constructors

ActionRef 

Fields

Instances

Instances details
Show ActionRef Source # 
Instance details

Defined in IHP.Router.DSL.AST

Eq ActionRef Source # 
Instance details

Defined in IHP.Router.DSL.AST

type Method = StdMethod Source #

HTTP methods recognised by the DSL. We reuse StdMethod from http-types rather than defining our own enum — it's the standard type used across WAI and the rest of the Haskell HTTP ecosystem.

methodFromText :: Text -> Maybe Method Source #

Parse a method name into a Method via http-types's parseMethod. ANY is handled by expandAnyMethod rather than here, because it expands to all methods rather than picking one.

methodToText :: Method -> Text Source #

Render a Method as its canonical uppercase name.

expandAnyMethod :: [Method] Source #

ANY expands to every StdMethod constructor.