Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

An implementation of chainable http middleware.

Wrap your http handlers in middleware to add functionality and reduce code duplication.

export default function chain() .then(add(requireHttpMethod("post"))) .then(add(requireAuthentication())) .then(send())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { HttpHandler } from "https://esm.town/v/emarref/HttpHandler";
import { HttpMiddleware } from "https://esm.town/v/emarref/HttpMiddleware";
import { internalServerError, success } from "https://esm.town/v/emarref/HttpResponse";
export type Chain = {
add: (middleware: HttpMiddleware) => Promise<Chain>;
send: (response: Response) => HttpHandler;
};
export function chain(): Promise<Chain> {
const stack = new Set<HttpMiddleware>();
async function getChain(): Promise<Chain> {
return { add, send };
}
const add: Chain["add"] = (middleware) => {
stack.add(middleware);
return getChain();
};
const send: Chain["send"] = (defaultResponse) => {
return async (request) => {
const queue = Array.from(stack);
let response = defaultResponse.clone();
let middleware: HttpMiddleware | undefined;
let happy = true;
async function loop() {
middleware = queue.shift();
if (!middleware) {
return;
}
const handler = middleware(async () => response);
try {
response = await handler(request);
} catch (err) {
happy = false;
if (err instanceof Response) {
response = err;
} else {
response = internalServerError(err);
}
}
}
do {
await loop();
} while (happy && middleware);
return response;
};
};
return getChain();
}
export function add(middleware: HttpMiddleware) {
return function({ add }: Chain) {
return add(middleware);
};
}
export function send(response?: Response) {
return function({ send }: Chain) {
return send(response ?? success());
};
}
June 14, 2024