Skip to content

Commit bc47305

Browse files
authored
Add ppx_deriving_router.cohttp_lwt (#8)
1 parent 5b081ac commit bc47305

File tree

12 files changed

+459
-3
lines changed

12 files changed

+459
-3
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
- run: opam install . --deps-only
4646
- run: opam exec -- dune build -p ppx_deriving_router
4747
# build with dream (should make ppx_deriving_router.dream available)
48-
- run: opam install dream --yes
48+
- run: opam install dream http cohttp cohttp-lwt cohttp-lwt-unix --yes
4949
- run: opam exec -- dune build -p ppx_deriving_router
5050
# run tests
5151
- run: opam install . --deps-only --with-test

cohttp-lwt/dune

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
(library
2+
(name ppx_deriving_router_cohttp_lwt)
3+
(public_name ppx_deriving_router.cohttp_lwt)
4+
(virtual_deps http cohttp cohttp-lwt cohttp-lwt-unix)
5+
(optional)
6+
(libraries ppx_deriving_router)
7+
(ppx_runtime_libraries ppx_deriving_router.cohttp_lwt_runtime)
8+
(kind ppx_deriver))

cohttp-lwt/runtime/dune

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(library
2+
(name ppx_deriving_router_runtime_cohttp_lwt_runtime)
3+
(public_name ppx_deriving_router.cohttp_lwt_runtime)
4+
(virtual_deps http cohttp cohttp-lwt cohttp-lwt-unix)
5+
(optional)
6+
(wrapped false)
7+
(libraries
8+
http
9+
cohttp
10+
cohttp-lwt
11+
cohttp-lwt-unix
12+
ppx_deriving_router.runtime_lib
13+
melange-json-native.ppx-runtime))
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
open struct
2+
module IO :
3+
Ppx_deriving_router_runtime_lib.IO with type 'a t = 'a Lwt.t = struct
4+
type 'a t = 'a Lwt.t
5+
6+
let return = Lwt.return
7+
let fail = Lwt.fail
8+
let bind = Lwt.bind
9+
let catch = Lwt_result.catch
10+
end
11+
12+
module Request :
13+
Ppx_deriving_router_runtime_lib.REQUEST
14+
with type t = Cohttp_lwt_unix.Request.t * Cohttp_lwt.Body.t
15+
and type 'a IO.t = 'a IO.t = struct
16+
module IO = IO
17+
18+
type t = Cohttp_lwt_unix.Request.t * Cohttp_lwt.Body.t
19+
20+
let queries (request, _body) =
21+
let uri = Cohttp_lwt_unix.Request.uri request in
22+
Uri.query uri
23+
|> List.map (fun (k, vs) -> List.map (fun v -> k, v) vs)
24+
|> List.flatten
25+
26+
let body ((_request, body) : t) = Cohttp_lwt.Body.to_string body
27+
28+
let path (request, _body) =
29+
let uri = Cohttp_lwt_unix.Request.uri request in
30+
Uri.path uri
31+
32+
let method_ (request, _body) =
33+
match Cohttp_lwt_unix.Request.meth request with
34+
| `GET -> `GET
35+
| `POST -> `POST
36+
| `PUT -> `PUT
37+
| `DELETE -> `DELETE
38+
| `HEAD -> failwith "HEAD is not supported"
39+
| `PATCH -> failwith "PATCH is not supported"
40+
| `OPTIONS -> failwith "OPTIONS is not supported"
41+
| `TRACE -> failwith "TRACE is not supported"
42+
| `CONNECT -> failwith "CONNECT is not supported"
43+
| `Other other ->
44+
failwith (Printf.sprintf "%s is not supported" other)
45+
end
46+
47+
module Response :
48+
Ppx_deriving_router_runtime_lib.RESPONSE
49+
with type t = Cohttp_lwt_unix.Response.t * Cohttp_lwt.Body.t
50+
and type status = Cohttp.Code.status_code
51+
and type 'a IO.t = 'a IO.t = struct
52+
module IO = IO
53+
54+
type t = Cohttp_lwt_unix.Response.t * Cohttp_lwt.Body.t
55+
type status = Cohttp.Code.status_code
56+
57+
let status_ok : status = `OK
58+
let status_not_found : status = `Not_found
59+
let status_bad_request : status = `Bad_request
60+
let status_method_not_allowed : status = `Method_not_allowed
61+
62+
let respond ~status ~headers body : t Lwt.t =
63+
let headers = Cohttp.Header.of_list headers in
64+
Cohttp_lwt_unix.Server.respond_string ~body ~status ~headers ()
65+
end
66+
67+
module Return :
68+
Ppx_deriving_router_runtime_lib.RETURN
69+
with type status = Cohttp.Code.status_code
70+
and type 'a t = 'a = struct
71+
type 'a t = 'a
72+
type status = Cohttp.Code.status_code
73+
74+
let data x = Some x
75+
let status _ = None
76+
let headers _ = []
77+
end
78+
end
79+
80+
include Ppx_deriving_router_runtime_lib.Make (Request) (Response) (Return)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
include
2+
Ppx_deriving_router_runtime_lib.S
3+
with type 'a IO.t = 'a Lwt.t
4+
and type Request.t = Cohttp_lwt_unix.Request.t * Cohttp_lwt.Body.t
5+
and type Response.t = Cohttp_lwt_unix.Response.t * Cohttp_lwt.Body.t
6+
and type Response.status = Cohttp.Code.status_code
7+
and type 'a Return.t = 'a

cohttp-lwt/test/dune

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(executable
2+
(name test)
3+
(preprocess
4+
(pps ppx_deriving_router.cohttp_lwt melange-json-native.ppx)))
5+
6+
(cram
7+
(deps
8+
./test.exe
9+
(package ppx_deriving_router)))

cohttp-lwt/test/routing.ml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
type modifier =
2+
| Uppercase
3+
| Lowercase
4+
(** this a custom type which we want to be able to serialize/deserialize
5+
from/to the URL query *)
6+
7+
let modifier_of_url_query k xs =
8+
match List.assoc_opt k xs with
9+
| Some "uppercase" -> Ok Uppercase
10+
| Some "lowercase" -> Ok Lowercase
11+
| Some _ -> Error "invalid modifier"
12+
| None -> Error "missing modifier"
13+
14+
let modifier_to_url_query k = function
15+
| Uppercase -> [ k, "uppercase" ]
16+
| Lowercase -> [ k, "lowercase" ]
17+
18+
module Options = struct
19+
open Ppx_deriving_json_runtime.Primitives
20+
21+
type t = { a : int option } [@@deriving json, url_query_via_json]
22+
end
23+
24+
module User_id : sig
25+
type t
26+
27+
val inject : string -> t
28+
val project : t -> string
29+
end = struct
30+
type t = string
31+
32+
let inject x = x
33+
let project x = x
34+
end
35+
36+
module Level = struct
37+
type t = Alert | Warning
38+
39+
let to_int = function Alert -> 2 | Warning -> 1
40+
41+
let of_int = function
42+
| 2 -> Alert
43+
| 1 -> Warning
44+
| _ -> failwith "invalid level"
45+
end
46+
47+
module Pages = struct
48+
open Ppx_deriving_router_runtime.Primitives
49+
50+
type user_id = User_id.t
51+
[@@deriving url_query_via_iso, url_path_via_iso]
52+
53+
type level = Level.t
54+
[@@deriving
55+
url_query_via_iso { t = int; inject = of_int; project = to_int }]
56+
57+
type t =
58+
| Home [@GET "/"]
59+
| Hello of {
60+
name : string;
61+
modifier : modifier option;
62+
greeting : string option;
63+
} [@GET "/hello/:name"]
64+
| Echo_options of { options : Options.t }
65+
| List_users of { user_ids : user_id list }
66+
| User_info of { user_id : user_id }
67+
| User_info_via_path of { user_id : user_id } [@GET "/user/:user_id"]
68+
| Signal of { level : level }
69+
| Route_with_implicit_path of { param : string option }
70+
| Route_with_implicit_path_post [@POST]
71+
[@@deriving router]
72+
end
73+
74+
module Api = struct
75+
open Ppx_deriving_router_runtime.Primitives
76+
open Ppx_deriving_json_runtime.Primitives
77+
78+
type user = { id : int } [@@deriving json]
79+
80+
type _ t =
81+
| List_users : user list t [@GET "/"]
82+
| Create_user : { id : int [@body] } -> user t [@POST "/"]
83+
| Get_user : { id : int } -> user t [@GET "/:id"]
84+
| Raw_response : Ppx_deriving_router_runtime.response t
85+
[@GET "/raw-response"]
86+
[@@deriving router]
87+
end
88+
89+
module All = struct
90+
type _ t =
91+
| Pages : Pages.t -> Ppx_deriving_router_runtime.response t
92+
[@prefix "/"]
93+
| Api : 'a Api.t -> 'a t [@prefix "/nested/api"]
94+
| Static : { path : string } -> Ppx_deriving_router_runtime.response t
95+
[@GET "/static/...path"]
96+
[@@deriving router]
97+
end

0 commit comments

Comments
 (0)