package wtr

  1. Overview
  2. Docs
Well Typed Router

Install

Dune Dependency

Authors

Maintainers

Sources

wtr-v1.0.0.tbz
sha256=2378a6c6cc723fb7d952e7931cef17f6e42bf9ef4143e79dce1e19da442d5aa1
sha512=1155173d1fdc58bb3016246ed328fb518dc0cc7772789263a9b613e6cbce9e309e78eb58093bd2caf90a4277e8794d3e98bd54731c2695be1e7b03d0cbdb1cca

Description

Wtr - A typed router for OCaml web applications

Published: 12 May 2021

README

Wtr - Well Typed Router

Wtr - A typed router for OCaml web applications.

User Guide          Wtr API

Overview

Wtr is typed router for OCaml web applications.

  • A trie based router. Route matching is efficient and fast.

  • Route handlers are type-checked during compilation.

  • Supports matching and capturing URI path components, eg /home/about/:int.

  • Supports matching and capturing URI query parameters, eg /home/about?q=:int&q1=hello.

  • Supports converting captured URI components to OCaml and custom user defined data types.

  • wtr.ppx is used to specify uri values. If you know how to type URI path in a browser location, then you already know how to use wtr.

  • Minimal learning overhead. Wtr is centered around just four API calls and a ppx - wtr.ppx.

    • {%wtr| /home/products/:int |} - creates a path and an infix function >- creates a route given a route handler.

    • Route handler is just a normal OCaml function.

    • Wtr.create - creates a router from a list of route values

    • Wtr.match' - matches a given uri path in a router.

    • Wtr.create_decoder - allows you to create a user defined decoder. see Fruit module in the demo below.

Wtr Demo

open! Wtr
open! Printf

(* User defined decoder. *)
module Fruit = struct
  type t =
    | Apple
    | Orange
    | Pineapple

  let t : t Wtr.decoder =
    Wtr.create_decoder ~name:"fruit" ~decode:(function
      | "apple" -> Some Apple
      | "orange" -> Some Orange
      | "pineapple" -> Some Pineapple
      | _ -> None )
end

let rec router () =
  create
    [ {%wtr| /home/about                           |} >- "about page"
    ; {%wtr| /home/:int/                           |} >- prod_page
    ; {%wtr| /home/:float/                         |} >- float_page
    ; {%wtr| /contact/*/:int                       |} >- contact_page
    ; {%wtr| /product/:string?section=:int&q=:bool |} >- product1
    ; {%wtr| /product/:string?section=:int&q1=yes  |} >- product2
    ; {%wtr| /fruit/:Fruit                         |} >- fruit_page
    ; {%wtr| /faq/:int/**                          |} >- faq
    ]

(* route handlers. *)
and prod_page i = "Product Page. Product Id : " ^ string_of_int i
and float_page f = "Float page. number : " ^ string_of_float f
and contact_page nm num = "Contact. Hi, " ^ nm ^ ". Num " ^ string_of_int num
and product1 name id q = sprintf "Product1 %s. Id: %d. q = %b" name id q
and product2 name id = sprintf "Product2 %s. Id: %d." name id

and fruit_page = function
  | Fruit.Apple -> "Apples are juicy!"
  | Orange -> "Orange is a citrus fruit."
  | Pineapple -> "Pineapple has scaly skin"

and faq category_id =
  let category_name =
    match category_id with
    | 1 -> "products"
    | 2 -> "insurance"
    | 3 -> "returns"
    | _ -> "unknown"
  in
  "FAQ page for category : " ^ category_name

let () =
  let router = router () in
  [ Wtr.match' router "/home/100001.1/"; Wtr.match' router "/home/100001/"
  ; Wtr.match' router "/home/about"
  ; Wtr.match' router "/product/dyson350?section=233&q=true"
  ; Wtr.match' router "/product/dyson350?section=2&q=false"
  ; Wtr.match' router "/product/dyson350?section=2&q1=yes"
  ; Wtr.match' router "/product/dyson350?section=2&q1=no"
  ; Wtr.match' router "/fruit/apple"; Wtr.match' router "/fruit/orange"
  ; Wtr.match' router "/fruit/pineapple"; Wtr.match' router "/fruit/guava" 
  ; Wtr.match' router "/faq/1/"
  ; Wtr.match' router "/faq/1/whatever"
  ; Wtr.match' router "/faq/2/whateasdfasdfasdf"
  ]
  |> List.iteri (fun i -> function
       | Some s -> Printf.printf "%3d: %s\n" (i + 1) s
       | None -> Printf.printf "%3d: None\n" (i + 1) );;

Output of the Demo

  1: Float page. number : 100001.1
  2: Product Page. Product Id : 100001
  3: about page
  4: Product1 dyson350. Id: 233. q = true
  5: Product1 dyson350. Id: 2. q = false
  6: Product2 dyson350. Id: 2.
  7: None
  8: Apples are juicy!
  9: Orange is a citrus fruit.
 10: Pineapple has scaly skin
 11: None
 12: FAQ page for category : products
 13: FAQ page for category : products
 14: FAQ page for category : insuranc

Dependencies (4)

  1. ppxlib >= "0.22.0"
  2. uri >= "4.2.0"
  3. ocaml >= "4.12.0"
  4. dune >= "2.8"

Dev Dependencies (2)

  1. odoc with-doc
  2. mdx with-test

Used by

None

Conflicts

None

OCaml

Innovation. Community. Security.