Reference

std/uri/route

std/uri/src/route.trb

TemplateCase, TemplateRoute and TemplateRoutes: URI templates typed against the cases of one type, which is what a router of std/web is built from (docs/design/WEB.md, decision D5; docs/design/URI.md section 9a).

The compiler checks a route where it is written: in route("/orders/{id}", to: Route.Order) the template literal gives the names and the case gives the fields, and a variable that is no field of the case, or a field without a default that is no variable, is an error at the literal. TemplateRoutes.of checks the same when the program starts, for routes made at run time, and it is what says that a case has no route.

type TemplateCase

type TemplateCase<Value> with Show, Equals, Hash

One case of Value, named where it is written: Route.Order where a TemplateCase<Route> is expected is the case Order, and not the function that constructs one (docs/design/URI.md section 9a). It is what a route pairs its template with.

Examples

type Route {
  case Home
  case Order(id: Int)
}

const order: TemplateCase<Route> = Route.Order
print order.name()

fn named

static fn named(name: String): TemplateCase<Value>

The case of Value called name, for a route made at run time. Nothing checks here that Value has such a case; TemplateRoutes.of does.

fn name

fn name(): String

The name of the case.

fn show

fn show(): String

Not documented.

type TemplateRoute

type TemplateRoute<Value> with Show

A template and the case of Value its variables fill: one line of a router.

field template

template: UriTemplate<Value>

The template, typed against Value.

field target

target: TemplateCase<Value>

The case a matched reference becomes, and the case whose values TemplateRoutes.link expands.

fn show

fn show(): String

Not documented.

fn route

fn route<Value>(template: UriTemplate<Value>, to: TemplateCase<Value>): TemplateRoute<Value>

The route of one case: route("/orders/{id}", to: Route.Order). Written with a literal and a case, it is checked where it is written: every variable is a field of the case, every field without a default is a variable, and a field with a default is at most a query variable ({?page}), which a request may leave out.

Examples

type Route {
  case Home
  case Order(id: Int)
}

const routes = TemplateRoutes.of([
  route("/", to: Route.Home),
  route("/orders/{id}", to: Route.Order),
])?

type TemplateRoutes

type TemplateRoutes<Value> with Show

Every route of Value, checked to cover each of its cases: a reference is matched against them in order and read into the case of the first that matches, and a value is linked through the route of its own case. Both directions come from the one template, so they cannot disagree.

Examples

type Route {
  case Home
  case Order(id: Int)
}

const routes = TemplateRoutes.of([
  route("/", to: Route.Home),
  route("/orders/{id}", to: Route.Order),
])?
const order: UriReference = "/orders/7"
print routes.matched(order)
print routes.link(Route.Order(7))

Pitfalls

  • The order matters where two templates match one reference: the first route wins.

fn of

static fn of(routes: List<TemplateRoute<Value>>): Result<TemplateRoutes<Value>, UriError> where Value: Describe

The routes, once every case of Value has one and every route fits its case: its case exists, every variable is a field of it, every field without a default is a variable, and a field with a default is at most a query variable. This is the check a program makes when it starts, and the one that finds a case without a route.

Errors

fn matched

fn matched(reference: UriReference): Value? where Value: Decode

The case the first matching route reads reference into, or None where no route matches it.

fn show

fn show(): String

Not documented.