Skip to content

Commit 49dac38

Browse files
committed
allow to define typed response
1 parent 5ecf4af commit 49dac38

File tree

6 files changed

+145
-121
lines changed

6 files changed

+145
-121
lines changed

native/lib/ppx_deriving_router.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,14 @@ let td_to_ty_handler param td =
7575
[%type:
7676
[%t td_to_ty (Some param) td] ->
7777
Ppx_deriving_router_runtime.request ->
78-
[%t param] Lwt.t]
78+
[%t param] Ppx_deriving_router_runtime.return Lwt.t]
7979
| None ->
8080
[%type:
8181
[%t td_to_ty param td] ->
8282
Ppx_deriving_router_runtime.request ->
83-
Ppx_deriving_router_runtime.response Lwt.t]
83+
Ppx_deriving_router_runtime.response
84+
Ppx_deriving_router_runtime.return
85+
Lwt.t]
8486

8587
let td_to_ty_enc param td =
8688
let loc = td.ptype_loc in

native/runtime/ppx_deriving_router_runtime_lib.ml

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
type http_method = [ `DELETE | `GET | `POST | `PUT ]
22

3-
type http_status =
4-
[ `Not_Found | `Bad_Request | `Method_Not_Allowed | `OK ]
5-
63
module type REQUEST = sig
74
type t
85

@@ -13,13 +10,26 @@ module type REQUEST = sig
1310
end
1411

1512
module type RESPONSE = sig
13+
type status
14+
15+
val status_ok : status
16+
val status_bad_request : status
17+
val status_not_found : status
18+
val status_method_not_allowed : status
19+
1620
type t
1721

1822
val respond :
19-
status:http_status ->
20-
headers:(string * string) list ->
21-
string ->
22-
t Lwt.t
23+
status:status -> headers:(string * string) list -> string -> t Lwt.t
24+
end
25+
26+
module type RETURN = sig
27+
type status
28+
type 'a t
29+
30+
val data : 'a t -> 'a option
31+
val status : _ t -> status option
32+
val headers : _ t -> (string * string) list
2333
end
2434

2535
module type S = sig
@@ -33,6 +43,10 @@ module type S = sig
3343

3444
type response = Response.t
3545

46+
module Return : RETURN
47+
48+
type 'a return = 'a Return.t
49+
3650
module Encode : module type of Ppx_deriving_router_encode
3751
module Decode : module type of Ppx_deriving_router_decode
3852
module Primitives : module type of Ppx_deriving_router_primitives
@@ -47,7 +61,7 @@ module type S = sig
4761
| Encode_raw : response encode
4862
| Encode_json : ('a -> json) -> 'a encode
4963

50-
val encode : 'a encode -> 'a -> response Lwt.t
64+
val encode : 'a encode -> 'a return -> response Lwt.t
5165

5266
type 'v route =
5367
| Route : ('a, 'v) Routes.path * 'a * ('v -> 'w) -> 'w route
@@ -80,15 +94,23 @@ module type S = sig
8094
end
8195
end
8296

83-
module Make (Request : REQUEST) (Response : RESPONSE) :
84-
S with type Request.t = Request.t and type Response.t = Response.t =
85-
struct
97+
module Make
98+
(Request : REQUEST)
99+
(Response : RESPONSE)
100+
(Return : RETURN with type status = Response.status) :
101+
S
102+
with type Request.t = Request.t
103+
and type Response.t = Response.t
104+
and type Response.status = Response.status
105+
and type 'a Return.t = 'a Return.t = struct
86106
type json = Yojson.Basic.t
87107
type request = Request.t
88108
type response = Response.t
109+
type 'a return = 'a Return.t
89110

90111
module Request = Request
91112
module Response = Response
113+
module Return = Return
92114
module Encode = Ppx_deriving_router_encode
93115
module Decode = Ppx_deriving_router_decode
94116
module Primitives = Ppx_deriving_router_primitives
@@ -103,14 +125,24 @@ struct
103125
| Encode_raw : response encode
104126
| Encode_json : ('a -> json) -> 'a encode
105127

106-
let encode : type a. a encode -> a -> response Lwt.t =
128+
let encode : type a. a encode -> a Return.t -> response Lwt.t =
107129
fun enc x ->
130+
let status =
131+
Option.value ~default:Response.status_ok (Return.status x)
132+
in
133+
let headers = Return.headers x in
108134
match enc, x with
109-
| Encode_raw, x -> Lwt.return x
110-
| Encode_json to_json, x ->
111-
Response.respond ~status:`OK
112-
~headers:[ "Content-Type", "application/json" ]
113-
(Yojson.Basic.to_string (to_json x))
135+
| Encode_raw, x -> (
136+
match Return.data x with
137+
| None -> Response.respond ~status ~headers ""
138+
| Some x -> Lwt.return x)
139+
| Encode_json to_json, x -> (
140+
match Return.data x with
141+
| None -> Response.respond ~status ~headers ""
142+
| Some x ->
143+
Response.respond ~status
144+
~headers:(("Content-Type", "application/json") :: headers)
145+
(Yojson.Basic.to_string (to_json x)))
114146

115147
type 'v route =
116148
| Route : ('a, 'v) Routes.path * 'a * ('v -> 'w) -> 'w route
@@ -151,16 +183,19 @@ struct
151183
Lwt.bind (dispatch router req) (function
152184
| `Ok v -> f v req
153185
| `Invalid_query_parameter (param, msg) ->
154-
Response.respond ~status:`Bad_Request ~headers:[]
186+
Response.respond ~status:Response.status_bad_request
187+
~headers:[]
155188
(Printf.sprintf "error processing query parameter %S: %s"
156189
param msg)
157190
| `Invalid_body reason ->
158-
Response.respond ~status:`Bad_Request ~headers:[]
191+
Response.respond ~status:Response.status_bad_request
192+
~headers:[]
159193
(Printf.sprintf "Invalid or missing request body: %s" reason)
160194
| `Method_not_allowed ->
161-
Response.respond ~status:`Method_Not_Allowed ~headers:[]
162-
"Method not allowed"
195+
Response.respond ~status:Response.status_method_not_allowed
196+
~headers:[] "Method not allowed"
163197
| `Not_found ->
164-
Response.respond ~status:`Not_Found ~headers:[] "Not found")
198+
Response.respond ~status:Response.status_not_found ~headers:[]
199+
"Not found")
165200
end
166201
end

native/runtime/ppx_deriving_router_runtime_lib.mli

Lines changed: 0 additions & 84 deletions
This file was deleted.

native/runtime_dream/ppx_deriving_router_runtime.ml

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
type 'a v = {
2+
data : 'a option;
3+
headers : (string * string) list;
4+
status : Dream.status option;
5+
}
6+
17
open struct
2-
module Request = struct
8+
module Request :
9+
Ppx_deriving_router_runtime_lib.REQUEST with type t = Dream.request =
10+
struct
311
type t = Dream.request
412

513
let queries = Dream.all_queries
@@ -15,12 +23,48 @@ open struct
1523
| _ -> failwith "Unsupported method"
1624
end
1725

18-
module Response = struct
26+
module Response :
27+
Ppx_deriving_router_runtime_lib.RESPONSE
28+
with type status = Dream.status
29+
and type t = Dream.response = struct
30+
type status = Dream.status
31+
32+
let status_ok : status = `OK
33+
let status_bad_request : status = `Bad_Request
34+
let status_method_not_allowed : status = `Method_Not_Allowed
35+
let status_not_found : status = `Not_Found
36+
1937
type t = Dream.response
2038

2139
let respond ~status ~headers body =
2240
Dream.respond ~status ~headers body
2341
end
42+
43+
module Return :
44+
Ppx_deriving_router_runtime_lib.RETURN
45+
with type status = Dream.status
46+
and type 'a t = 'a v = struct
47+
type status = Dream.status
48+
49+
type 'a t = 'a v = {
50+
data : 'a option;
51+
headers : (string * string) list;
52+
status : status option;
53+
}
54+
55+
let data x = x.data
56+
let status x = x.status
57+
let headers x = x.headers
58+
end
2459
end
2560

26-
include Ppx_deriving_router_runtime_lib.Make (Request) (Response)
61+
include Ppx_deriving_router_runtime_lib.Make (Request) (Response) (Return)
62+
63+
module Return = struct
64+
include Return
65+
66+
type 'a t = 'a v
67+
68+
let return ?status ?(headers = []) data =
69+
Lwt.return { data = Some data; headers; status }
70+
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
1+
type 'a v = {
2+
data : 'a option;
3+
headers : (string * string) list;
4+
status : Dream.status option;
5+
}
6+
17
include
28
Ppx_deriving_router_runtime_lib.S
39
with type Request.t = Dream.request
410
and type Response.t = Dream.response
11+
and type Response.status = Dream.status
12+
and type 'a Return.t = 'a v
13+
14+
module Return : sig
15+
include Ppx_deriving_router_runtime_lib.RETURN with type 'a t = 'a v
16+
17+
val return :
18+
?status:Dream.status ->
19+
?headers:(string * string) list ->
20+
'a ->
21+
'a return Lwt.t
22+
end

native/test/test.ml

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
open Routing
22
open Lwt.Infix
33

4+
let return = Ppx_deriving_router_runtime.Return.return
5+
46
let pages_handle route _req =
57
match route with
6-
| Pages.Home -> Dream.html "HOME PAGE"
8+
| Pages.Home -> return (Dream.response "HOME PAGE")
79
| Route_with_implicit_path { param } ->
810
let param = Option.value ~default:"-" param in
9-
Dream.html ("works as well, param is: " ^ param)
10-
| Route_with_implicit_path_post -> Dream.html "posted"
11+
return (Dream.response ("works as well, param is: " ^ param))
12+
| Route_with_implicit_path_post -> return (Dream.response "posted")
1113
| Hello { name; modifier } ->
1214
let name =
1315
match modifier with
@@ -16,22 +18,29 @@ let pages_handle route _req =
1618
| Some Lowercase -> String.lowercase_ascii name
1719
in
1820
let greeting = Printf.sprintf "Hello, %s!" name in
19-
Dream.html greeting
21+
return (Dream.response greeting)
2022

2123
let pages_handler = Pages.handle pages_handle
2224

23-
let api_handle : type a. a Api.t -> Dream.request -> a Lwt.t =
25+
let api_handle :
26+
type a.
27+
a Api.t -> Dream.request -> a Ppx_deriving_router_runtime.return Lwt.t
28+
=
2429
fun x _req ->
2530
match x with
26-
| Raw_response -> Dream.respond "RAW RESPONSE"
27-
| List_users -> Lwt.return []
28-
| Create_user { id } -> Lwt.return { Api.id }
29-
| Get_user { id } -> Lwt.return { Api.id }
31+
| Raw_response -> return (Dream.response "RAW RESPONSE")
32+
| List_users -> return []
33+
| Create_user { id } -> return { Api.id }
34+
| Get_user { id } -> return { Api.id }
3035

3136
let api_handler : Dream.handler = Api.handle { f = api_handle }
3237

3338
let all_handler : Dream.handler =
34-
let f : type a. a All.t -> Dream.request -> a Lwt.t =
39+
let f :
40+
type a.
41+
a All.t ->
42+
Dream.request ->
43+
a Ppx_deriving_router_runtime.return Lwt.t =
3544
fun x req ->
3645
match x with
3746
| Pages p -> pages_handle p req

0 commit comments

Comments
 (0)