routes

Typed routing for OCaml applications
Legend:
Library
Module
Module type
Parameter
Class
Class type
Library routes
Module Routes
type ('a, 'b) path

path represents a sequence of path parameter patterns that are expected in a route.

type ('a, 'b) target

target represents a combination of a sequence of path params, and whether that sequence should consider trailing slash parameters or not. Its analogous to a URI target.

  • since 0.8.0
type 'b route

route is a combination of a path sequence, with a function that will be called on a successful match. When a path sequence matches, the patterns that are extracted are forwarded to said function with the types that the user defined. Note that because of value restriction, the route definitions will be assigned a weak type by the compiler. This causes problems if one intends to re-use the same route definition in multiple contexts, like using a single definition for both matching a target url, and serializing to use in a client call. To avoid such problems one can use eta-expansion (i.e. add an explicit argument to the route definition).

Example:

let route () = Routes.(s "foo" / str / int /? nil @-->
  (fun (a : string) (b : int) ->
      Printf.sprintf "%s %d" a b))
type 'b router

router is a collection of multiple routes. It transforms a list of routes into a trie like structure, that is then used for matching an input target url.

val int : ( 'a, 'b ) path -> ( int -> 'a, 'b ) path

int matches a path segment if it can be successfully coerced into an integer.

val int32 : ( 'a, 'b ) path -> ( int32 -> 'a, 'b ) path

int32 matches a path segment if it can be successfully coerced into a 32 bit integer.

val int64 : ( 'a, 'b ) path -> ( int64 -> 'a, 'b ) path

int64 matches a path segment if it can be successfully coerced into a 64 bit integer.

val str : ( 'a, 'b ) path -> ( string -> 'a, 'b ) path

str matches any path segment and forwards it as a string.

val bool : ( 'a, 'b ) path -> ( bool -> 'a, 'b ) path

bool matches a path segment if it can be successfully coerced into a boolean.

val s : string -> ( 'a, 'b ) path -> ( 'a, 'b ) path

s word matches a path segment if it exactly matches word. The matched path param is then discarded.

val nil : ( 'a, 'a ) path

nil is used to end a sequence of path parameters.

val empty : ( 'a, 'a ) target

empty is used to represent an empty route. This is useful for matching a route that equals "/" or "".

  • since 0.8.0
val pattern : ( 'c -> string ) -> ( string -> 'c option ) -> string -> ( 'a, 'b ) path -> ( 'c -> 'a, 'b ) path

pattern accepts two functions, one for converting a user provided type to a string representation, and another to potentially convert a string to the said type. With these two functions, it creates a pattern that can be used for matching a path segment. This is useful when there is a need for types that aren't provided out of the box by the library. It also accepts a string label that will be used when pretty printing the route pattern. it is recommended to use a string value starting with `:` character for the label, example: ':shape', ':float' etc

Example:

type shape =
  | Square
  | Circle

let shape_of_string = function
  | "square" -> Some Square
  | "circle" -> Some Circle
  | _ -> None

let shape_to_string = function
  | Square -> "square"
  | Circle -> "circle"

let shape = Routes.pattern shape_to_string shape_of_string

(* Now the shape pattern can be used just like any
   of the built in patterns like int, bool etc *)
let route () = s "shape" / shape / s "create" /? nil
val (/) : ( ( 'a, 'b ) path -> 'c ) -> ( 'd -> ( 'a, 'b ) path ) -> 'd -> 'c

l / r joins two path match patterns l and r into a pattern sequence, parse l followed by parse r. Example: If we want to define a route that matches a string followd by a constant "foo" and then an integer, we'd use the / operator like below:

let route () = Routes.(str / s "foo" / int /? nil)
val (/?) : ( 'a -> ( 'b, 'c ) path ) -> 'a -> ( 'b, 'c ) target

l /? r is used to express the sequence of, parse l followed by parse r and then stop parsing. This is used at the end of the route pattern to define how a route should end. The right hand parameter r should be a pattern definition that cannot be used in further chains joined by /.

/? also indicates that a route needs to finish without a trailing slash.

val (//?) : ( 'a -> ( 'b, 'c ) path ) -> 'a -> ( 'b, 'c ) target

//? is similar to /? with the difference that it is used to create a route that must finish with a trailing slash.

  • since 0.8.0
val (@-->) : ( 'a, 'b ) target -> 'a -> 'b route

r @--> h is used to connect a route pattern r to a function h that gets called if this pattern is successfully matched.

val one_of : 'b route list -> 'b router

one_of accepts a list of tuples comprised of route definitions of type 'b route where 'b is the type that a successful route match will return.

It transforms the input list of routes into a trie like structure that can later be used to perform route matches.

val match' : 'a router -> target:string -> 'a option

match' accepts a router and the target url to match.

val sprintf : ( 'a, string ) target -> 'a

sprintf takes a route pattern as an input, and returns a string with the result of formatting the pattern into a URI path.

val pp_target : Format.formatter -> ( 'a, 'b ) target -> unit

pp_target can be used to pretty-print a sequence of path params. This can be useful to get a human readable output that indicates the kind of pattern that a route will match. When creating a custom pattern matcher using pattern, a string label needs to be provided. This label is used by pp_target when preparing the pretty-print output.

Example:

let r () = Routes.(s "foo" / int / s "add" / bool);;
Format.asprintf "%a" Routes.pp_target r;;
-: "foo/:int/add/:bool"
  • since 0.8.0
val pp_route : Format.formatter -> 'a route -> unit

pp_route is similar to pp_target, except it takes a route (combination of path sequence and a handler) as input, instead of just a path sequence.

val add_route : 'b route -> 'b router -> 'b router

add_route takes a route and a router as input, and returns a new router which contains the route provided as input.

  • since 0.7.3