Created
August 7, 2018 17:04
-
-
Save mrmurphy/607d9f41a7f121229ac8690fd1f705e0 to your computer and use it in GitHub Desktop.
Type Safe Reason Express Handlers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Prom is a library that provides | |
<$> (map) | |
and | |
>>= (bind, or flatMap) | |
for promises. | |
*/ | |
open Prom; | |
/* | |
A Handler is a more functional and type-safe way of dealing with composable "middleware" in the express chain. | |
This lets the user chain handlers that can either respond to the request with their own response (in the case | |
of something like an unauthorized request) or pass along some new information to the next function in line. | |
The types are structured such that a chain must always be ended before it can be used by express. Thus | |
providing a good degree of type safety around the middleware experience with, hopefully, minimum complexity. | |
Should be used something like this: | |
startWith(thing that converts a request to some data or response) | |
|. andThen(some other thing that adds more data or responds) | |
|. andThen(some other thing that adds more data or responds) | |
|. endWith(some thing that turns that data into a response) | |
*/ | |
module Status = Express.Response.StatusCode; | |
type intermediateResult('a) = | |
| Respond(Express.Response.StatusCode.t, Js.Json.t) | |
| Continue('a); | |
type middle('a, 'b) = | |
(Express.Request.t, 'a) => Js.Promise.t(intermediateResult('b)); | |
type endResult = (Status.t, Js.Json.t); | |
type end_('a) = (Express.Request.t, 'a) => Js.Promise.t(endResult); | |
let startWith = | |
(fn: Express.Request.t => Js.Promise.t(intermediateResult('a))) | |
: middle(unit, 'a) => | |
(req, _) => fn(req); | |
let andThen = | |
(source: middle('a, 'b), next: middle('b, 'c)) | |
: middle('a, 'b) => | |
(req, a) => | |
source(req, a) | |
>>= ( | |
resB => | |
switch (resB) { | |
| Respond(code, content) => | |
Js.Promise.resolve(Respond(code, content)) | |
| Continue(b) => next(req, b) | |
} | |
); | |
let endWith = | |
(middleware: middle(unit, 'b), end_: end_('b)) | |
: Express.Middleware.t => | |
Express.PromiseMiddleware.from((_next, req, res) => | |
middleware(req, ()) | |
>>= ( | |
resB => | |
switch (resB) { | |
| Continue(b) => | |
end_(req, b) | |
<$> ( | |
((status, content)) => | |
res | |
|> Express.Response.status(status) | |
|> Express.Response.sendJson(content) | |
) | |
| Respond(status, content) => | |
Js.Promise.resolve( | |
res | |
|> Express.Response.status(status) | |
|> Express.Response.sendJson(content), | |
) | |
} | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment