Skip to content

Commit 5ecb867

Browse files
committed
feat(behavioral): add chain-of-responsibility pattern
1 parent 4c9dee8 commit 5ecb867

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import http from "http";
2+
3+
type HandlerClass = { new (handler?: Handler): Handler };
4+
5+
abstract class Handler {
6+
constructor(private readonly handler?: Handler) {}
7+
8+
process(req: http.IncomingMessage, res: http.ServerResponse) {
9+
console.log("BaseHandler: processing");
10+
11+
if (!this.handler) {
12+
res.writeHead(404, { "Content-Type": "application/json" });
13+
res.write(JSON.stringify({ error: 404, message: "Not found" }));
14+
return res.end();
15+
}
16+
17+
this.handler.process(req, res);
18+
}
19+
}
20+
21+
class AuthorizationHandler extends Handler {
22+
constructor(nextHandler?: Handler) {
23+
super(nextHandler);
24+
}
25+
26+
process(req: http.IncomingMessage, res: http.ServerResponse) {
27+
console.log("AuthorizationHandler: processing");
28+
29+
const authorization = req.headers.authorization;
30+
const token = authorization?.split(" ")?.[1];
31+
32+
// implementation of authorization process
33+
if (token) return super.process(req, res);
34+
35+
res.writeHead(401, { "Content-Type": "application/json" });
36+
res.write(JSON.stringify({ error: 401, message: "Not Authorized" }));
37+
return res.end();
38+
}
39+
}
40+
41+
class UsersHandler extends Handler {
42+
static users = [{ name: "Aram" }, { name: "Anri" }];
43+
44+
async process(req: http.IncomingMessage, res: http.ServerResponse) {
45+
console.log("UsersHandler: processing");
46+
47+
res.writeHead(200, { "Content-Type": "application/json" });
48+
res.write(JSON.stringify({ users: UsersHandler.users }));
49+
res.end();
50+
}
51+
}
52+
class HttpServer {
53+
constructor(private readonly handlers: Record<string, Handler> = {}) {}
54+
55+
get(route: string, ...Handlers: HandlerClass[]) {
56+
const requestHandler = this.buildChain(Handlers);
57+
this.handlers[route] = requestHandler;
58+
}
59+
60+
listen(port: number) {
61+
const server = http.createServer(this.baseHandler.bind(this));
62+
server.listen(port);
63+
}
64+
65+
// utility functions
66+
private buildChain(Handlers: HandlerClass[]): Handler {
67+
return Handlers.reduceRight(
68+
(previousHandler: Handler | undefined, CurrentHandler: HandlerClass) => {
69+
return new CurrentHandler(previousHandler);
70+
},
71+
undefined
72+
)!;
73+
}
74+
75+
private baseHandler(req: http.IncomingMessage, res: http.ServerResponse) {
76+
for (const [route, handler] of Object.entries(this.handlers)) {
77+
if (req.url === route) return handler.process(req, res);
78+
}
79+
}
80+
}
81+
82+
const app = new HttpServer();
83+
84+
app.get("/users", AuthorizationHandler, UsersHandler);
85+
86+
app.listen(3000);

0 commit comments

Comments
 (0)