Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/drup/furl
Formatted url
https://github.com/drup/furl
format gadt ocaml uri
Last synced: about 16 hours ago
JSON representation
Formatted url
- Host: GitHub
- URL: https://github.com/drup/furl
- Owner: Drup
- License: mit
- Created: 2015-04-27T05:06:56.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2025-01-20T14:14:53.000Z (about 21 hours ago)
- Last Synced: 2025-01-20T15:26:43.821Z (about 20 hours ago)
- Topics: format, gadt, ocaml, uri
- Language: OCaml
- Homepage:
- Size: 82 KB
- Stars: 49
- Watchers: 9
- Forks: 3
- Open Issues: 12
-
Metadata Files:
- Readme: Readme.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Formatted Url
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][re] and [uri][uri][re]: https://github.com/ocaml/ocaml-re
[uri]: https://github.com/mirage/ocaml-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
```## Quick look
Let's imagine we want to build a REST service indexing [Camelidaes](https://species.wikimedia.org/wiki/Camelidae).
```ocaml
let camlidae () = Furl.host "www.camlidae.ml"
```We can query a Camelidae by name:
```ocaml
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:
```ocaml
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:
```ocaml
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:
```ocaml
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:
```ocaml
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:
```ocaml
fetch_http @@ query_by_hump 2 (Some false) ;;
["Bactrian camel"; "Wild camel"]
```See [camlidae.ml](test/camlidae.ml) for the complete working example.
## Principles
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.