~/bend-docscommunity

air/router.bend checks

raw source on the hub · import 0x1efee7e6292e6267db2ca5c7e267456a/air/router.bend as Router

3 imports
import Base
import ./text.bend as Text
import ./http.bend as Http

Types

type Seg source · line 19 · raw

Data

One segment of a route pattern. Rest is *name: it must be last and binds the remaining path, joined with "/", possibly "".

type Route source · line 49 · raw

Type

slash remembers whether the pattern ended with a slash, for the strict policy.

type Slash source · line 269 · raw

Data

What a trailing slash means. Ignore (the default) treats "/a/" and "/a" as the same path. Strict matches a route only when the request and the pattern agree on the slash. Redirect answers 308 to the path without the slash, query kept, and never redirects "/".

type Pick source · line 325 · raw

Type

The outcome of walking the routes. Hit is an exact match. Fallback is a GET route found while serving HEAD, kept unless an explicit HEAD route turns up later. Miss carries the methods routes offered for this path, so 405 and OPTIONS can list them.

type Ask source · line 378 · raw

Data

What the walk needs from the request, computed once: its path split into segments, its method's name, and the slash and star flags.

Definitions

def Handler source · line 14 · raw

Type

def classify source · line 24 · raw

@+s:String -> Seg

def parse_pattern.go source · line 33 · raw

@segs:List<&2, String> -> @acc:List<&2, Seg> -> List<&2, Seg>

def parse_pattern source · line 40 · raw

@+path:String -> List<&2, Seg>

def has_slash source · line 44 · raw

@+path:String -> Bool

Whether a path ends with a slash that is not the root's.

def new source · line 52 · raw

@method:0x1efee7e6292e6267db2ca5c7e267456a/air/http.Method -> @+path:String -> @handler:Handler -> Route

def get source · line 55 · raw

@path:String -> @handler:Handler -> Route

def post source · line 58 · raw

@path:String -> @handler:Handler -> Route

def put source · line 61 · raw

@path:String -> @handler:Handler -> Route

def delete source · line 64 · raw

@path:String -> @handler:Handler -> Route

def patch source · line 67 · raw

@path:String -> @handler:Handler -> Route

def options source · line 77 · raw

@path:String -> @handler:Handler -> Route

An OPTIONS route is optional: without one, OPTIONS answers 204 with the methods the path allows.

def mount.go source · line 86 · raw

@+prefix:List<&2, Seg> -> @routes:List<&1, Route> -> List<&1, Route>

Prefixes every route with prefix: "/api" + "/users/:id" is "/api/users/:id". The prefix may hold params; a wildcard in it would make every route under it unreachable.

def mount source · line 93 · raw

@prefix:String -> @routes:List<&1, Route> -> List<&1, Route>

def append_routes source · line 96 · raw

@xs:List<&1, Route> -> @ys:List<&1, Route> -> List<&1, Route>

def all source · line 104 · raw

@groups:List<&1, List<&1, Route>> -> List<&1, Route>

Joins route groups in order: all([pages(), mount("/api", api())]).

def seg_shape source · line 114 · raw

@seg:Seg -> String

def shape.go source · line 123 · raw

@pat:List<&2, Seg> -> @rev:String -> String

def shape source · line 132 · raw

@pat:List<&2, Seg> -> String

The shape of a pattern, params and wildcards anonymized: "/users/:/*". Two routes with the same method and shape conflict.

def shape_with_slash source · line 142 · raw

@pat:List<&2, Seg> -> @slash:Bool -> String

The shape with the pattern's trailing slash, so "/s" and "/s/" are two keys: the strict policy tells them apart, and under the others the first registered wins.

def rest_misplaced source · line 150 · raw

@pat:List<&2, Seg> -> Bool

A wildcard anywhere but last can never match.

def conflicts.note source · line 161 · raw

@acc:List<&2, String> -> @key:String -> @misplaced:Bool -> @dup:Bool -> List<&2, String>

def conflicts.go source · line 170 · raw

@routes:List<&1, Route> -> @+seen:Map<&2, String> -> @acc:List<&2, String> -> List<&2, String>

def conflicts source · line 184 · raw

@routes:List<&1, Route> -> List<&2, String>

Every problem in a route list, one line each, in list order: "duplicate route: GET /users/:" or "wildcard not last: GET /a/*/b". Empty when the list is clean. The list is consumed.

def check.report source · line 187 · raw

@problems:List<&2, String> -> IO(Unit)

def check.fin source · line 196 · raw

@problems:List<&2, String> -> @clean:Bool -> IO(Unit)

def check source · line 207 · raw

@routes:List<&1, Route> -> IO(Unit)

Prints each conflict and ends the process with code 1; returns quietly when the routes are clean. Call it in main before serving.

def pattern_of source · line 212 · raw

@routes:List<&1, Route> -> List<&2, List<&2, Seg>>

The patterns of a route list, handlers dropped; for laws.

def bind_segment.lit source · line 222 · raw

@m:Map<&2, String> -> @same:Bool -> Maybe<&2, Map<&2, String>>

def bind_segment source · line 230 · raw

@m:Map<&2, String> -> @seg:Seg -> @+s:String -> Maybe<&2, Map<&2, String>>

A Param binds the request segment; a Lit must equal it.

def join_rest source · line 240 · raw

@segs:List<&2, String> -> @rev:String -> String

The remaining segments joined with "/": ["a", "b"] is "a/b", [] is "".

def match_path source · line 247 · raw

@pat:List<&2, Seg> -> @segs:List<&2, String> -> @params:Maybe<&2, Map<&2, String>> -> Maybe<&2, Map<&2, String>>

def is_strict source · line 274 · raw

@policy:Slash -> Bool

def slash_ok source · line 285 · raw

@strict:Bool -> @route_slash:Bool -> @path_slash:Bool -> Bool

Under the strict policy a route is only considered when its slash agrees with the request's.

def gate source · line 288 · raw

@ok:Bool -> @m:Maybe<&2, Map<&2, String>> -> Maybe<&2, Map<&2, String>>

def drop_slashes source · line 295 · raw

@+s:String -> String

def with_query source · line 302 · raw

@path:String -> @qs:String -> String

def redirect_target.fin source · line 309 · raw

@pq:0x1efee7e6292e6267db2ca5c7e267456a/air/text.Two -> String

def redirect_target source · line 315 · raw

@+target:String -> String

Where a redirected request goes: the raw target, undecoded, minus its trailing slashes, query kept.

def mark source · line 330 · raw

@m:Map<&2, String> -> @name:String -> Map<&2, String>

def marked source · line 333 · raw

@+m:Map<&2, String> -> @name:String -> Bool

def with_head source · line 336 · raw

@+m:Map<&2, String> -> @has_get:Bool -> Map<&2, String>

def render_allow source · line 345 · raw

@+allowed:Map<&2, String> -> String

The Allow value: the methods offered, plus HEAD when GET is, plus OPTIONS, sorted and joined with ", ".

def consider.fin source · line 350 · raw

@acc:Pick -> @handler:Handler -> @name:String -> @same:Bool -> @head_get:Bool -> @matched:Maybe<&2, Map<&2, String>> -> Pick

Folds one path-matching route into the pick. same is an exact method match, head_get a GET route seen by a HEAD request.

def star_match source · line 369 · raw

@star:Bool -> @matched:Maybe<&2, Map<&2, String>> -> Maybe<&2, Map<&2, String>>

OPTIONS * asks about the server, not a path: every route counts as matching and none is run.

def consider.route source · line 381 · raw

@acc:Pick -> @route:Route -> @+ask:Ask -> Pick

def consider source · line 395 · raw

@acc:Pick -> @route:Route -> @+ask:Ask -> Pick

def select source · line 404 · raw

@routes:List<&1, Route> -> @acc:Pick -> @+ask:Ask -> Pick

def pick source · line 412 · raw

@+policy:Slash -> @routes:List<&1, Route> -> @+req:0x1efee7e6292e6267db2ca5c7e267456a/air/http.Request -> Pick

Walks the routes for the request under the slash policy.

def miss.pick source · line 419 · raw

@+allowed:Map<&2, String> -> @options:Bool -> @none:Bool -> 0x1efee7e6292e6267db2ca5c7e267456a/air/http.Response

A path no route knows is 404. One that routes know under other methods is 405 with Allow, or 204 with Allow when the request is OPTIONS.

def miss source · line 428 · raw

@+allowed:Map<&2, String> -> @options:Bool -> 0x1efee7e6292e6267db2ca5c7e267456a/air/http.Response

def run source · line 431 · raw

@pick:Pick -> @+req:0x1efee7e6292e6267db2ca5c7e267456a/air/http.Request -> IO(0x1efee7e6292e6267db2ca5c7e267456a/air/http.Response)

def describe.miss source · line 440 · raw

@+allowed:Map<&2, String> -> @none:Bool -> String

def describe source · line 448 · raw

@pick:Pick -> String

What a pick would do, in a word; for laws. A miss lists its Allow.

def dispatch.go source · line 457 · raw

@+policy:Slash -> @routes:List<&1, Route> -> @+req:0x1efee7e6292e6267db2ca5c7e267456a/air/http.Request -> @redirect:Bool -> IO(0x1efee7e6292e6267db2ca5c7e267456a/air/http.Response)

def is_redirect source · line 465 · raw

@policy:Slash -> Bool

def dispatch_with source · line 478 · raw

@+policy:Slash -> @routes:List<&1, Route> -> @+req:0x1efee7e6292e6267db2ca5c7e267456a/air/http.Request -> IO(0x1efee7e6292e6267db2ca5c7e267456a/air/http.Response)

Runs the first route whose method and path match the request under the slash policy. HEAD runs the GET route when no HEAD route matches. A path that matches only under other methods answers 405 with Allow, or 204 with Allow to OPTIONS; no match answers 404.

def dispatch source · line 482 · raw

@routes:List<&1, Route> -> @+req:0x1efee7e6292e6267db2ca5c7e267456a/air/http.Request -> IO(0x1efee7e6292e6267db2ca5c7e267456a/air/http.Response)

dispatch_with under the default policy: a trailing slash is ignored.