I’ve tried something recently in a project with Dream.
Suppose you have an url like /page/param1/param2/ : you want to be able to do three things:
Build this url in the application in a safe way, which mean : param1 -> param2 -> string
Create a route which handle this url pattern (the compilation should fail if you don’t handle all the arguments)
Ensure the handler will have the signature param1 -> param2 -> Dream.handler
Of course, some pages will have two arguments, some other three, and you have to find a way represent this in the type system.
For this, I’ve used a gadt:
type ('a, 'b) t =
| Static : string * ('a, 'b) t -> (unit -> 'a, 'b) t
| Int : string * ('a, 'b) t -> (int64 -> 'a, 'b) t
| String : string * ('a, 'b) t -> (string -> 'a, 'b) t
| End : ('a, 'a) t
The string is the parameter name in the url (id, login, …) and the gadt make the representation for this parameter in the type system. This gives me a way to declare some urls in the application:
val root : (unit -> 'a, 'a) t
(** The path to root / *)val topic_url : (string -> 'a, 'a) t
(** The path to /:topic *)val thread_url : (string -> int64 -> 'a, 'a) t
(** The path to /:topic/:thread *)
Then I have some some functions wihch handle this gadt:
val repr : (unit -> ('a, 'b) t) -> string(** Represent the route associated with this path *)val unzip : (unit -> ('a, 'b) t) -> (string -> string) -> 'a -> 'b(** Extract the parameters from the request.
[unzip path extract f] will apply the function extract for all the
arguments in the path, and gives them to f
The function [extract] is given in argument in order to break dependency
circle.
This should be something like:
let extract_param request name =
Dream.param request name |> Dream.from_percent_encoded
*)
Thanks for your reply. I’m still not sure if I have managed to wrap my head around this 😕 I guess I need to re-read the relevant chapter from RWO book. I’ll post back here I’m finally able to understand handler in your case.
If you want something more detailed, there is a library which does the same things (with more documentation inside :)) : https://github.com/anuragsoni/routes
I’ve tried something recently in a project with Dream.
Suppose you have an url like
/page/param1/param2/
: you want to be able to do three things:Of course, some pages will have two arguments, some other three, and you have to find a way represent this in the type system.
For this, I’ve used a gadt:
type ('a, 'b) t = | Static : string * ('a, 'b) t -> (unit -> 'a, 'b) t | Int : string * ('a, 'b) t -> (int64 -> 'a, 'b) t | String : string * ('a, 'b) t -> (string -> 'a, 'b) t | End : ('a, 'a) t
The string is the parameter name in the url (id, login, …) and the gadt make the representation for this parameter in the type system. This gives me a way to declare some urls in the application:
val root : (unit -> 'a, 'a) t (** The path to root / *) val topic_url : (string -> 'a, 'a) t (** The path to /:topic *) val thread_url : (string -> int64 -> 'a, 'a) t (** The path to /:topic/:thread *)
Then I have some some functions wihch handle this gadt:
val repr : (unit -> ('a, 'b) t) -> string (** Represent the route associated with this path *) val unzip : (unit -> ('a, 'b) t) -> (string -> string) -> 'a -> 'b (** Extract the parameters from the request. [unzip path extract f] will apply the function extract for all the arguments in the path, and gives them to f The function [extract] is given in argument in order to break dependency circle. This should be something like: let extract_param request name = Dream.param request name |> Dream.from_percent_encoded *)
Thanks for your reply. I’m still not sure if I have managed to wrap my head around this 😕 I guess I need to re-read the relevant chapter from RWO book. I’ll post back here I’m finally able to understand
handler
in your case.If you want something more detailed, there is a library which does the same things (with more documentation inside :)) : https://github.com/anuragsoni/routes