Skip to content

Commit 4974fe3

Browse files
committed
Provide bindings for NextJs req and res types
1 parent 194cd85 commit 4974fe3

File tree

3 files changed

+110
-48
lines changed

3 files changed

+110
-48
lines changed

src/RestNextJs.res

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,43 @@ module Exn = {
1616
@inline
1717
let panic = message => Exn.raiseError(Exn.makeError(`[rescript-rest] ${message}`))
1818

19-
type options<'input, 'req, 'res> = {
19+
type req = private {
20+
cookies: Js.Dict.t<string>,
21+
method: Rest.method,
22+
url: string,
23+
port: int,
24+
body: Js.Json.t,
25+
query: Js.Json.t,
26+
headers: Js.Dict.t<string>,
27+
rawHeaders: array<string>,
28+
rawTrailers: array<string>,
29+
aborted: bool,
30+
complete: bool,
31+
statusCode: Rest.Response.numiricStatus,
32+
statusMessage: string,
33+
trailers: Js.Dict.t<string>,
34+
}
35+
// @send
36+
// external destroy: (req, ~error: option<Js.Exn.t>=?) => bool = "destroy"
37+
38+
type reply
39+
type rec res = private {
40+
statusCode: Rest.Response.numiricStatus,
41+
statusMessage: string,
42+
getHeader: string => option<string>,
43+
setHeader: (string, string) => unit,
44+
status: int => res,
45+
end: unit => reply,
46+
json: Js.Json.t => reply,
47+
// The type is not 100% correct.
48+
// It asccepts a string, object or a Buffer
49+
send: Js.Json.t => reply,
50+
}
51+
52+
type options<'input> = {
2053
input: 'input,
21-
req: 'req,
22-
res: 'res,
54+
req: req,
55+
res: res,
2356
}
2457

2558
let handler = (route, implementation) => {
@@ -41,40 +74,38 @@ let handler = (route, implementation) => {
4174
)
4275
}
4376

44-
async (genericReq, genericRes) => {
45-
let req = genericReq->Obj.magic
46-
let res = genericRes->Obj.magic
47-
48-
if req["method"] !== definition.method {
49-
res["status"](404)["end"]()
50-
}
51-
switch req->S.parseOrThrow(inputSchema) {
52-
| input =>
53-
try {
54-
let implementationResult = await implementation({
55-
req: genericReq,
56-
res: genericRes,
57-
input,
58-
})
59-
let data: {..} = implementationResult->S.reverseConvertOrThrow(responseSchema)->Obj.magic
60-
let headers: option<dict<string>> = data["headers"]
61-
switch headers {
62-
| Some(headers) =>
63-
headers
64-
->Js.Dict.keys
65-
->Js.Array2.forEach(key => {
66-
res["setHeader"](key, headers->Js.Dict.unsafeGet(key))
77+
async (req, res) => {
78+
if req.method !== definition.method {
79+
res.status(404).end()
80+
} else {
81+
switch req->S.parseOrThrow(inputSchema) {
82+
| input =>
83+
try {
84+
let implementationResult = await implementation({
85+
req,
86+
res,
87+
input,
6788
})
68-
| None => ()
89+
let data: {..} = implementationResult->S.reverseConvertOrThrow(responseSchema)->Obj.magic
90+
let headers: option<dict<string>> = data["headers"]
91+
switch headers {
92+
| Some(headers) =>
93+
headers
94+
->Js.Dict.keys
95+
->Js.Array2.forEach(key => {
96+
res.setHeader(key, headers->Js.Dict.unsafeGet(key))
97+
})
98+
| None => ()
99+
}
100+
res.status(%raw(`data.status || 200`)).json(data["data"])
101+
} catch {
102+
| S.Raised(error) =>
103+
Js.Exn.raiseError(
104+
`Unexpected error in the ${definition.path} route: ${error->S.Error.message}`,
105+
)
69106
}
70-
res["status"](%raw(`data.status || 200`))["json"](data["data"])
71-
} catch {
72-
| S.Raised(error) =>
73-
Js.Exn.raiseError(
74-
`Unexpected error in the ${definition.path} route: ${error->S.Error.message}`,
75-
)
107+
| exception S.Raised(error) => res.status(400).send(error->S.Error.message->Js.Json.string)
76108
}
77-
| exception S.Raised(error) => res["status"](400)["send"](error->S.Error.message)
78109
}
79110
}
80111
}

src/RestNextJs.res.js

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/RestNextJs.resi

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,43 @@
11
@@uncurried
22

3-
type options<'input, 'req, 'res> = {
3+
type req = private {
4+
cookies: Js.Dict.t<string>,
5+
method: Rest.method,
6+
url: string,
7+
port: int,
8+
body: Js.Json.t,
9+
query: Js.Json.t,
10+
headers: Js.Dict.t<string>,
11+
rawHeaders: array<string>,
12+
rawTrailers: array<string>,
13+
aborted: bool,
14+
complete: bool,
15+
statusCode: Rest.Response.numiricStatus,
16+
statusMessage: string,
17+
trailers: Js.Dict.t<string>,
18+
}
19+
20+
type reply
21+
type rec res = private {
22+
statusCode: Rest.Response.numiricStatus,
23+
statusMessage: string,
24+
getHeader: string => option<string>,
25+
setHeader: (string, string) => unit,
26+
status: int => res,
27+
end: unit => reply,
28+
json: Js.Json.t => reply,
29+
// The type is not 100% correct.
30+
// It asccepts a string, object or a Buffer
31+
send: Js.Json.t => reply,
32+
}
33+
34+
type options<'input> = {
435
input: 'input,
5-
req: 'req,
6-
res: 'res,
36+
req: req,
37+
res: res,
738
}
839

940
let handler: (
1041
Rest.route<'input, 'response>,
11-
options<'input, 'req, 'res> => promise<'response>,
12-
) => ('req, 'res) => promise<'reply>
42+
options<'input> => promise<'response>,
43+
) => (req, res) => promise<reply>

0 commit comments

Comments
 (0)