package routes

  1. Overview
  2. Docs
Typed routing for OCaml applications

Install

Dune Dependency

Authors

Maintainers

Sources

routes-0.7.0.tbz
sha256=0b67b3837302ccea4c0d42e463f2edbde6408d651b5e65e74cd694656d44f0be
sha512=775b7037cda4f784b31942df2c96787f64c56ab95d9399ac6a59426958abb19b830e974daeae6a4e53c6d04f5f6673006af5e7cefd4db5a27b2bf66ce2ac17d6

Description

routes provides combinators for adding typed routing to OCaml applications. The core library will be independent of any particular web framework or runtime. It does path based dispatch from a target url to a user provided handler.

Tags

router http

Published: 21 Mar 2020

README

Routes  

This library will help with adding typed routes to OCaml applications. The goal is to have a easy to use portable library with reasonable performance See benchmark folder.

Users can create a list of routes, and handler function to work on the extracted entities using the combinators provided by the library. To perform URL matching one would just need to forward the URL's path and query to the matcher.

Example
# #require "routes";;
# type req = { target: string };;
type req = { target : string; }

# let idx (_ : req) = "root";;
val idx : req -> string = <fun>

# let get_user (id : int) (req : req) = Printf.sprintf "Received request from %s to fetch id: %d" req.target id;;
val get_user : int -> req -> string = <fun>

# let search_user (name: string) (city: string) (_req : req) = "search for user";;
val search_user : string -> string -> req -> string = <fun>

# let routes = Routes.(
    one_of [
      nil @--> idx
    ; (s "user" / int /? nil) @--> get_user
    ; (s "user" / str / str /? trail) @--> search_user
    ]);;
val routes : (req -> string) Routes.router = <abstr>

# let req = { target = "/user/12" };;
val req : req = {target = "/user/12"}

# match Routes.match' ~target:"/some/url" routes with None -> "No match" | Some r -> r req;;
- : string = "No match"

# match Routes.match' ~target:req.target routes with None -> "No match" | Some r -> r req;;
- : string = "Received request from /user/12 to fetch id: 12"

# match Routes.match' ~target:"/user/hello/world/" routes with None -> "No match" | Some r -> r req;;
- : string = "search for user"

# match Routes.match' ~target:"/user/hello/world" routes with None -> "No match because of missing trailing slash" | Some r -> r req;;
- : string = "No match because of missing trailing slash"

# let my_fancy_route () = Routes.(s "user" / int / s "add" /? nil);;
val my_fancy_route : unit -> (int -> 'a, 'a) Routes.path = <fun>

# let print_route = Routes.sprintf @@ my_fancy_route ();;
val print_route : int -> string = <fun>

# print_route 12;;
- : string = "/user/12/add"

It is possible to define custom patterns that can be used for matching.

# open Routes;;
# type shape = Circle | Square
type shape = Circle | Square

# let shape_of_string = function "circle" -> Some Circle | "square" -> Some Square | _ -> None
val shape_of_string : string -> shape option = <fun>

# let shape_to_string = function Circle -> "circle" | Square -> "square"
val shape_to_string : shape -> string = <fun>

# let shape = pattern shape_to_string shape_of_string ":shape"
val shape : ('_weak1, '_weak2) path -> (shape -> '_weak1, '_weak2) path =
  <fun>

# let process_shape (s : shape) = shape_to_string s
val process_shape : shape -> string = <fun>

# let route () = s "shape" / shape / s "create" /? nil
val route : unit -> (shape -> '_weak3, '_weak3) path = <fun>

# sprintf (route ())
- : shape -> string = <fun>

# sprintf (route ()) Square
- : string = "/shape/square/create"

# let router = one_of [ route () @--> process_shape ]
val router : string router = <abstr>

# match' ~target:"/shape/circle/create" router
- : string option = Some "circle"

# match' ~target:"/shape/square/create" router
- : string option = Some "square"

# match' ~target:"/shape/triangle/create" router
- : string option = None

# Format.asprintf "%a" pp_path (route ())
- : string = "/shape/:shape/create"

Installation

To use the version published on opam:
opam install routes
For development version:
opam pin add routes git+https://github.com/anuragsoni/routes.git

Related Work

The combinators are influenced by Rudi Grinberg's wonderful blogpost about type safe routing done via an EDSL using GADTs + an interpreted for the DSL.

Also thanks to Gabriel Radanne for feedback and for the blog post showing the technique used in printf like functions.

Dependencies (2)

  1. dune >= "2.1"
  2. ocaml >= "4.06.1"

Dev Dependencies (2)

  1. mdx with-test & < "2.0"
  2. alcotest with-test

Used by (1)

  1. current_web = "0.2"

Conflicts

None

OCaml

Innovation. Community. Security.