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
66
67
68
69
70
71
72
73
74
|
(* Import the StdLabels module which provides labeled versions of standard library functions *)
open StdLabels
(* Import the Routes library for type-safe HTTP routing *)
open Routes
(* Import Piaf for HTTP types like Method.t *)
open Piaf
(* Create a custom Map module keyed by HTTP methods (GET, POST, etc.) *)
(* This allows us to organize routes by their HTTP verb *)
module R = Map.Make (struct
(* The key type is Piaf's Method.t (represents HTTP methods) *)
type t = Method.t
(* Define how to compare two HTTP methods for ordering in the map *)
let compare a b =
(* Convert methods to strings (e.g., "GET", "POST") *)
let a_str = Method.to_string a in
let b_str = Method.to_string b in
(* Use standard string comparison *)
String.compare a_str b_str
;;
end)
(* Define all routes in the application *)
let routes =
(* Use fold_left to build up a map of routes *)
List.fold_left
(* For each (verb, route) pair, add the route to the map under that verb *)
~f:(fun acc (v, r) -> R.add_to_list v r acc) (* Start with an empty map *)
~init:R.empty
(* List of (HTTP method, route pattern -> handler) tuples *)
[ `GET, (s "posts" /? nil) @--> Handler.get_posts
(* `GET - HTTP GET method *)
(* s "posts" - matches the literal string "posts" *)
(* /? - path concatenation operator *)
(* nil - end of path (no more segments) *)
(* @--> - binds the route pattern to the handler function *)
(* Handler.get_posts - the function that handles this route *)
; `GET, (s "posts" / int /? nil) @--> Handler.get_post
(* / int - captures an integer parameter (post ID) *)
; `GET, (s "comments" / int /? nil) @--> Handler.get_comment
(* Get a single comment by ID *)
; `GET, (s "users" / str / s "comments" /? nil) @--> Handler.get_user_comments
(* / str - captures a string parameter (username) *)
; `GET, (s "posts" / int / s "comments" /? nil) @--> Handler.get_post_comments
(* Get all comments for a specific post *)
; `GET, (s "comments" / int / s "children" /? nil) @--> Handler.get_comment_children
(* Get child comments (replies) for a comment *)
]
;;
(* Transform the routes map by applying 'one_of' to each list of routes *)
(* 'one_of' combines multiple routes into a single router that tries each in order *)
let router = R.map one_of routes
(* Function to match an incoming request against our routes *)
let match_route verb path =
(* Try to find routes for the given HTTP verb in our map *)
match R.find_opt verb router with
(* If we have routes for this verb, try to match the path *)
| Some router ->
(* Use the Routes library's match' function to find a matching route *)
(match match' router ~target:path with
(* Exact match - the path matches completely *)
| FullMatch r -> Some r
(* Match with trailing slash - e.g., "/posts" matches "/posts/" *)
| MatchWithTrailingSlash r -> Some r
(* No routes matched the path *)
| NoMatch -> None)
(* We don't have any routes for this HTTP verb *)
| None -> None
;;
|