Source file router.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
open Misc
open Sexplib.Std

module Co = Cohttp
module Rock = Rock
module Route = Route

open Rock

type 'a t = (Route.t * 'a) Queue.t array [@@deriving sexp]

let create () = Array.init 7 (fun _ -> Queue.create ())

let int_of_meth = function
  | `GET     -> 0
  | `POST    -> 1
  | `PUT     -> 2
  | `DELETE  -> 3
  | `HEAD    -> 4
  | `PATCH   -> 5
  | `OPTIONS -> 6
  | _        -> failwith "non standard http verbs not supported"

let get t meth = t.(int_of_meth meth)

let add t ~route ~meth ~action =
  Queue.push (route, action) t.(int_of_meth meth)

(** finds matching endpoint and returns it with the parsed list of
    parameters *)
let matching_endpoint endpoints meth uri =
  let endpoints = get endpoints meth in
  endpoints
    |> Queue.find_map ~f:(fun ep ->
      uri |> Route.match_url (fst ep) |> Option.map ~f:(fun p -> (ep, p)))

module Env = struct
  let key : Route.matches Hmap0.key =
    Hmap0.Key.create ("path_params",[%sexp_of: Route.matches])
end

(* not param_exn since if the endpoint was selected it's likely that
   the parameter is already there *)
let param req param =
  let { Route.params;  _ } =
    Hmap0.find_exn Env.key (Request.env req) in
  List.assoc param params

let splat req =
  Hmap0.find_exn Env.key (Request.env req)
  |> Route.splat

(* takes a list of endpoints and a default handler. calls an endpoint
   if a match is found. otherwise calls the handler *)
let m endpoints =
  let filter default req =
    let url = req |> Request.uri |> Uri.path in
    match matching_endpoint endpoints (Request.meth req) url with
    | None -> default req
    | Some (endpoint, params) -> begin
        let env_with_params =
          Hmap0.add Env.key params (Request.env req) in
        (snd endpoint) { req with Request.env=env_with_params }
      end
  in Rock.Middleware.create ~name:"Router" ~filter