This library allows to create type-safe formatted urls in the spirit of the
format
type from the standard library. It is backed by re and uri
This is work in progress, if you have any remarks or proposition, please open an issue. The API will be changed until I'm happy with it. Contributions are welcome. Also, it may still be buggy.
To use this library, you can pin it:
opam pin add furl https://github.com/Drup/furl.git
Let's imagine we want to build a REST service indexing Camelidaes.
let camlidae () = Furl.host "www.camlidae.ml"
We can query a Camelidae by name:
let by_name () =
Furl.(~$camlidae / "name" /% String /? nil)
val by_name : unit -> (string -> 'a, 'a) Furl.furl
Notice how the type of the value describes the contained parameters.
Let's consider the type ('f,'r) Furl.furl
. 'f
is the type of a function
corresponding to the parameters of the url. 'r
is the return type, which could be anything at this point.
We can also query a list of camelidae by humps:
let by_humps () =
Furl.(~$camlidae / "humps" /% Int /? nil)
val by_humps : unit -> (int -> 'a, 'a) Furl.furl
This is nice, but we want to refine the list by humps to only show non extinct camelidaes:
let by_humps () =
Furl.(~$camlidae / "humps" /% Int /? ("extinct",Opt Bool) ** nil)
val by_humps : unit -> (int -> bool option -> 'a, 'a) Furl.furl
We can now build a handler answering to these endpoints:
let handle_camlidaes =
Furl.match_url [
Furl.(route ~$by_name) (fun n ->
List.filter (fun c -> c.name = n) list_camlidaes
) ;
Furl.(route ~$by_humps) (fun humps -> function
| None ->
List.filter (fun c -> c.humps = humps) list_camlidaes
| Some b ->
List.filter (fun c -> c.humps = humps && c.extinct = b) list_camlidaes
);
]
~default:(fun _uri -> failwith "This is not a camlidae.")
val handle_camlidaes : Uri.t -> camlidae list
You can then give this handler to your favorite web server and Tada, a camelidae web API.
You can also expose the formatted urls for clients:
let query_by_humps = Furl.eval @@ by_humps ()
val query_by_humps : int -> bool option -> Uri.t
Then you can use your favorite http client to get the answer we all want:
fetch_http @@ query_by_hump 2 (Some false) ;;
["Bactrian camel"; "Wild camel"]
See camlidae.ml for the complete working example.
furl uses GADT in a similar manner than format in the standard library, but specialized for urls and regexps. The matching against multiple uris is done with re.
urls are separated into Furl.url
which are not yet finalized and Furl.furl
which are finalized. This separation is done to make Furl.url
a pure datastructure that can be serialized, moved around (and sent to the client in the context of eliom). Furl.furl
contains an url
and the list of converters.