Skip to content

Commit 99a0a5f

Browse files
committed
adds code for chapters 06...08`
1 parent b42c1e1 commit 99a0a5f

File tree

7 files changed

+402
-0
lines changed

7 files changed

+402
-0
lines changed

src/chapter_06.1/index.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const http = require("node:http");
2+
3+
const PORT = 5255;
4+
5+
const server = http.createServer((request, response) => {
6+
const { headers, data, statusCode } = handleRequest(request);
7+
response.writeHead(statusCode, headers);
8+
response.end(data);
9+
});
10+
11+
// The header that needs to be sent on every response.
12+
const baseHeader = {
13+
"Content-Type": "text/plain",
14+
};
15+
16+
const routeHandlers = {
17+
"GET /": () => ({ statusCode: 200, data: "Hello World!", headers: { "My-Header": "Hello World!" } }),
18+
"POST /echo": () => ({ statusCode: 201, data: "Yellow World!", headers: { "My-Header": "Yellow World!" } }),
19+
};
20+
21+
const handleRequest = ({ method, url }) => {
22+
const handler =
23+
routeHandlers[`${method} ${url}`] ||
24+
(() => ({ statusCode: 404, data: "Not Found", headers: { "My-Header": "Not Found" } }));
25+
26+
const { statusCode, data } = handler();
27+
const headers = { ...baseHeader, "Content-Length": Buffer.byteLength(data) };
28+
29+
return { headers, statusCode, data };
30+
};
31+
32+
server.listen(PORT, () => {
33+
console.log(`Server is listening at :${PORT}`);
34+
});

src/chapter_06.2/index.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const http = require("node:http");
2+
3+
const PORT = 5255;
4+
5+
class Router {
6+
constructor() {
7+
this.routes = {};
8+
}
9+
10+
addRoute(method, path, handler) {
11+
this.routes[`${method} ${path}`] = handler;
12+
}
13+
14+
handleRequest(request, response) {
15+
const { url, method } = request;
16+
const handler = this.routes[`${method} ${url}`];
17+
18+
if (!handler) {
19+
return console.log("404 Not found");
20+
}
21+
22+
handler(request, response);
23+
}
24+
25+
printRoutes() {
26+
console.log(Object.entries(this.routes));
27+
}
28+
}
29+
30+
const router = new Router();
31+
router.addRoute("GET", "/", function handleGetBasePath(req, res) {
32+
console.log("Hello from GET /");
33+
res.end();
34+
});
35+
36+
router.addRoute("POST", "/", function handlePostBasePath(req, res) {
37+
console.log("Hello from POST /");
38+
res.end();
39+
});
40+
41+
// Note: We're using an arrow function instead of a regular function now
42+
let server = http.createServer((req, res) => router.handleRequest(req, res));
43+
server.listen(PORT);

src/chapter_06.3/index.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
const http = require("node:http");
2+
3+
const PORT = 5255;
4+
5+
const HTTP_METHODS = {
6+
GET: "GET",
7+
POST: "POST",
8+
PUT: "PUT",
9+
DELETE: "DELETE",
10+
PATCH: "PATCH",
11+
HEAD: "HEAD",
12+
OPTIONS: "OPTIONS",
13+
CONNECT: "CONNECT",
14+
TRACE: "TRACE",
15+
};
16+
17+
class Router {
18+
constructor() {
19+
this.routes = {};
20+
}
21+
22+
#addRoute(method, path, handler) {
23+
if (typeof path !== "string" || typeof handler !== "function") {
24+
throw new Error("Invalid argument types: path must be a string and handler must be a function");
25+
}
26+
this.routes[`${method} ${path}`] = handler;
27+
}
28+
29+
handleRequest(request, response) {
30+
const { url, method } = request;
31+
const handler = this.routes[`${method} ${url}`];
32+
33+
if (!handler) {
34+
return console.log("404 Not found");
35+
}
36+
37+
handler(request, response);
38+
}
39+
40+
get(path, handler) {
41+
this.#addRoute(HTTP_METHODS.GET, path, handler);
42+
}
43+
44+
post(path, handler) {
45+
this.#addRoute(HTTP_METHODS.POST, path, handler);
46+
}
47+
48+
put(path, handler) {
49+
this.#addRoute(HTTP_METHODS.PUT, path, handler);
50+
}
51+
52+
delete(path, handler) {
53+
this.#addRoute(HTTP_METHODS.DELETE, path, handler);
54+
}
55+
56+
patch(path, handler) {
57+
this.#addRoute(HTTP_METHODS.PATCH, path, handler);
58+
}
59+
60+
head(path, handler) {
61+
this.#addRoute(HTTP_METHODS.HEAD, path, handler);
62+
}
63+
64+
options(path, handler) {
65+
this.#addRoute(HTTP_METHODS.OPTIONS, path, handler);
66+
}
67+
68+
connect(path, handler) {
69+
this.#addRoute(HTTP_METHODS.CONNECT, path, handler);
70+
}
71+
72+
trace(path, handler) {
73+
this.#addRoute(HTTP_METHODS.TRACE, path, handler);
74+
}
75+
76+
printRoutes() {
77+
console.log(Object.entries(this.routes));
78+
}
79+
}
80+
81+
const router = new Router();
82+
83+
router.get("/", function handleGetBasePath(req, res) {
84+
console.log("Hello from GET /");
85+
res.end();
86+
});
87+
88+
router.post("/", function handlePostBasePath(req, res) {
89+
console.log("Hello from POST /");
90+
res.end();
91+
});
92+
93+
// Note: We're using an arrow function instead of a regular function now
94+
let server = http.createServer((req, res) => router.handleRequest(req, res));
95+
server.listen(PORT);

src/chapter_07/challenge_1.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class TrieNode {
2+
isEndOfWord = false;
3+
children = new Map();
4+
}
5+
6+
class Trie {
7+
constructor() {
8+
this.root = new TrieNode();
9+
}
10+
11+
insert(word, node = this.root) {
12+
const wordLength = word.length;
13+
14+
// Exit condition: If the word to insert is empty, terminate the recursion.
15+
if (wordLength === 0) return;
16+
17+
for (let idx = 0; idx < wordLength; idx++) {
18+
let char = word[idx];
19+
20+
// Check if the current node has a child node for the current character.
21+
if (!node.children.has(char)) {
22+
// If not, create a new TrieNode for this character and add it to the children of the current node.
23+
node.children.set(char, new TrieNode());
24+
}
25+
26+
// Move to the child node corresponding to the current character.
27+
node = node.children.get(char);
28+
}
29+
30+
node.isEndOfWord = true;
31+
}
32+
}

src/chapter_07/challenge_2.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
class TrieNode {
2+
isEndOfWord = false;
3+
children = new Map();
4+
}
5+
6+
class Trie {
7+
constructor() {
8+
this.root = new TrieNode();
9+
}
10+
11+
search(word) {
12+
// Initialize 'currentNode' to the root node of the Trie.
13+
let currentNode = this.root;
14+
15+
// Loop through each character in the input word.
16+
for (let index = 0; index < word.length; index++) {
17+
// Check if the current character exists as a child node
18+
// of the 'currentNode'.
19+
if (currentNode.children.has(word[index])) {
20+
// If it does, update 'currentNode' to this child node.
21+
currentNode = currentNode.children.get(word[index]);
22+
} else {
23+
// If it doesn't, the word is not in the Trie. Return false.
24+
return false;
25+
}
26+
}
27+
28+
// After looping through all the characters, check if the 'currentNode'
29+
// marks the end of a word in the Trie.
30+
return currentNode.isEndOfWord;
31+
}
32+
33+
insert(word, node = this.root) {
34+
const wordLength = word.length;
35+
36+
if (wordLength === 0) return;
37+
38+
for (let idx = 0; idx < wordLength; idx++) {
39+
let char = word[idx];
40+
41+
if (!node.children.has(char)) {
42+
node.children.set(char, new TrieNode());
43+
}
44+
45+
node = node.children.get(char);
46+
}
47+
48+
node.isEndOfWord = true;
49+
}
50+
}

src/chapter_08/challenge_1.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
class RouteNode {
2+
constructor() {
3+
// Create a Map to store children nodes
4+
this.children = new Map();
5+
6+
// Initialize the handler to null
7+
this.handler = null;
8+
}
9+
}
10+
11+
class TrieRouter {
12+
constructor() {
13+
// Create a root node upon TrieRouter instantiation
14+
this.root = new RouteNode();
15+
}
16+
17+
addRoute(path, handler) {
18+
// Validate input types
19+
if (typeof path !== "string" || path[0] !== "/") throw new Error("Malformed path provided.");
20+
if (typeof handler !== "function") throw new Error("Handler should be a function");
21+
22+
// Start at the root node of the Trie
23+
let currentNode = this.root;
24+
// Split the path into segments and filter out empty segments
25+
let routeParts = path.split("/").filter(Boolean);
26+
27+
// Loop through all segments of the route
28+
for (let idx = 0; idx < routeParts.length; idx++) {
29+
const segment = routeParts[idx].toLowerCase();
30+
if (segment.includes(" ")) throw new Error("Malformed path parameter");
31+
32+
// Attempt to find the next node in the Trie
33+
let childNode = currentNode.children.get(segment);
34+
35+
// If the next node doesn't exist, create it
36+
if (!childNode) {
37+
childNode = new RouteNode();
38+
currentNode.children.set(segment, childNode);
39+
}
40+
41+
// Move to the next node for the next iteration
42+
currentNode = childNode;
43+
}
44+
45+
// Assign the handler to the last node
46+
currentNode.handler = handler;
47+
}
48+
49+
printTree(node = this.root, indentation = 0) {
50+
const indent = "-".repeat(indentation);
51+
52+
node.children.forEach((childNode, segment) => {
53+
console.log(`${indent}${segment}`);
54+
this.printTree(childNode, indentation + 1);
55+
});
56+
}
57+
}
58+
59+
const trieRouter = new TrieRouter();
60+
61+
function ref() {}
62+
63+
trieRouter.addRoute("/home/", ref);
64+
trieRouter.addRoute("/user/status/play", function inline() {});
65+
66+
trieRouter.printTree();

0 commit comments

Comments
 (0)