You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[Challenge 2: Add the dynamic routing functionality in `Router` class](/chapters/ch06.8-ex-dynamic-routing#challenge-2-add-the-dynamic-routing-functionality-in-router-class)
-[Challenge 2: Add the dynamic routing functionality in `Router` class](/chapters/ch06.9-ex-dynamic-routing#challenge-2-add-the-dynamic-routing-functionality-in-router-class)
Copy file name to clipboardExpand all lines: chapters/ch06.6-ex-implementing-router.md
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -519,3 +519,5 @@ null
519
519
```
520
520
521
521
Everything seems to be working well. This is it for the `findRoute` method. This was much easier than our `addRoute` implementation, since we only cared about searching. Excellent, we've grasped the basics well! Now let's move on to the more advanced features in the next chapter, ie Implementing HTTP methods with our router.
Copy file name to clipboardExpand all lines: chapters/ch06.7-ex-adding-http-methods.md
+60-67Lines changed: 60 additions & 67 deletions
Original file line number
Diff line number
Diff line change
@@ -57,10 +57,6 @@ Go ahead and add the functionality to our `TrieRouter` class. This will involve
57
57
Here's the solution I came up with:
58
58
59
59
```js
60
-
functiongetRouteParts(path) {
61
-
/** stays the same **/
62
-
}
63
-
64
60
constHTTP_METHODS= {
65
61
GET:"GET",
66
62
POST:"POST",
@@ -73,88 +69,66 @@ const HTTP_METHODS = {
73
69
TRACE:"TRACE",
74
70
};
75
71
76
-
classRouter {
72
+
classRouteNode {
77
73
constructor() {
78
-
this.rootNode=newRouteNode();
74
+
this.children=newMap();
75
+
this.handler=newMap();
79
76
}
77
+
}
80
78
81
-
addRoute(path, method, handler) {
82
-
if (typeof path !="string"||typeof handler !="function"||typeof method !="string") {
83
-
thrownewError(
84
-
"Invalid params sent to the `addRoute` method. `path` should be of the type `string`, `method` should be a valid HTTP verb and of type `string` and `handler` should be of the type `function`"
if (typeof path !=="string"|| path[0] !=="/") thrownewError("Malformed path provided.");
86
+
if (typeof handler !=="function") thrownewError("Handler should be a function");
87
+
if (!HTTP_METHODS[method]) thrownewError("Invalid HTTP Method");
104
88
105
-
let nextNode =node.children.get(currPart);
89
+
let currentNode =this.root;
90
+
let routeParts =path.split("/").filter(Boolean);
106
91
107
-
if (!nextNode) {
108
-
nextNode =newRouteNode();
109
-
node.children.set(currPart, nextNode);
110
-
}
92
+
for (let idx =0; idx <routeParts.length; idx++) {
93
+
constsegment= routeParts[idx].toLowerCase();
94
+
if (segment.includes("")) thrownewError("Malformed `path` parameter");
111
95
112
-
if (idx ==routeParts.length-1) {
113
-
nextNode.handler.set(method, handler);
96
+
let childNode =currentNode.children.get(segment);
97
+
if (!childNode) {
98
+
childNode =newRouteNode();
99
+
currentNode.children.set(segment, childNode);
114
100
}
115
101
116
-
node=nextNode;
102
+
currentNode=childNode;
117
103
}
104
+
currentNode.handler.set(method, handler); // Changed this line
118
105
}
119
106
120
107
findRoute(path, method) {
121
-
if (path.endsWith("/")) path =path.substring(0, path.length-1);
122
-
123
-
let routeParts =getRouteParts(path);
124
-
let node =this.rootNode;
125
-
let handler =null;
108
+
let segments =path.split("/").filter(Boolean);
109
+
let currentNode =this.root;
126
110
127
-
for (let idx =0; idx <routeParts.length; idx++) {
128
-
let currPart = routeParts[idx];
129
-
130
-
let nextNode =node.children.get(currPart);
131
-
132
-
if (!nextNode) break;
111
+
for (let idx =0; idx <segments.length; idx++) {
112
+
constsegment= segments[idx];
133
113
134
-
if (idx ==routeParts.length-1) {
135
-
handler =nextNode.handler.get(method);
114
+
let childNode =currentNode.children.get(segment);
115
+
if (childNode) {
116
+
currentNode = childNode;
117
+
} else {
118
+
returnnull;
136
119
}
137
-
138
-
node = nextNode;
139
120
}
140
121
141
-
return handler;
122
+
returncurrentNode.handler.get(method); // Changed this line
142
123
}
143
124
144
-
printTree(node=this.rootNode, indentation=0) {
145
-
/** unchanged **/
146
-
}
147
-
}
148
-
149
-
classRouteNode {
150
-
constructor() {
151
-
this.handler=newMap();
152
-
this.children=newMap();
125
+
printTree(node=this.root, indentation=0) {
126
+
/** Unchanged **/
153
127
}
154
128
}
155
129
```
156
130
157
-
The new HTTP method implementation introduces several key changes to extend the existing router implementation to support HTTP methods. Below are the details of what was changed and why:
131
+
The new HTTP method implementation introduces only some minor key changes to extend the existing router implementation to support HTTP methods. Below are the details of what was changed and why:
158
132
159
133
```js
160
134
constHTTP_METHODS= {
@@ -182,19 +156,38 @@ class TrieRouter {
182
156
In our `TrieRouter` class, we updated the `addRoute` method. It now takes an additional argument, `method`, which specifies the HTTP method for the route.
if (typeof path !=="string"|| path[0] !=="/") thrownewError("Malformed path provided.");
161
+
if (typeof handler !=="function") thrownewError("Handler should be a function");
162
+
163
+
// New check for HTTP method
164
+
if (!HTTP_METHODS[method]) thrownewError("Invalid HTTP Method");
165
+
...
166
+
}
186
167
```
187
168
188
-
The error handling has been updated to ensure the `method` is also a string.
169
+
The error handling has been updated to ensure the `method` is a valid HTTP method.
189
170
190
171
```js
191
-
method=method.toUpperCase();
172
+
this.handler=newMap();
192
173
```
193
174
194
-
The `method` string is converted to uppercase to standardize the HTTP methods.
175
+
The `handler` in `RouteNode` has changed from a single function reference to a `Map`. This allows you to store multiple handlers for the same path but with different HTTP methods.
195
176
196
177
```js
197
-
this.handler=newMap();
178
+
addRoute(path, method, handler) {
179
+
...
180
+
// Previous -> currentNode.handler = handler;
181
+
currentNode.handler.set(method, handler);
182
+
}
183
+
184
+
findRoute(path, method) {
185
+
...
186
+
// Previous -> return currentNode.handler;
187
+
returncurrentNode.handler.get(method); // Changed this line
188
+
}
198
189
```
199
190
200
-
The `handler` in `RouteNode` has changed from a single function reference to a `Map`. This allows you to store multiple handlers for the same path but with different HTTP methods.
191
+
In both the `addRoute` and `findRoute` methods, we've updated the line that sets and gets the handler for a specific path. Now, the handler is stored in the `handler` map of the current node, with the HTTP method as the key.
In this exercise, we will improve our `TrieRouter` API by implementing support for HTTP verbs (GET, POST, PUT, DELETE, etc.) directly instead of using raw strings. Let's look at our current implementation of the `TrieRouter`:
4
+
5
+
```js
6
+
trieRouter.addRoute("GET", "/users", () => {});
7
+
trieRouter.addRoute("GET", "/", () => {});
8
+
```
9
+
10
+
As you could already feel, this approach is not very flexible and uses raw strings, which can lead to typing errors, and has no auto-completion support unfortunately. Let's improve this by adding support for HTTP methods directly to the `TrieRouter` API.
11
+
12
+
Firstly, we've added dedicated methods for each HTTP method in the `TrieRouter` class. This allows users to define routes more intuitively using method-specific calls like `trieRouter.get('/home', handler)` for the GET method and `trieRouter.post('/home', handler)` for the POST method.
Firstly, we've added dedicated methods for each HTTP method in the `TrieRouter` class. This allows users to define routes more intuitively using method-specific calls like `trieRouter.get('/home', handler)` for the GET method and `trieRouter.post('/home', handler)` for the POST method.
66
+
67
+
In each of these methods, we call the existing `addRoute` method, passing the appropriate HTTP method from the `HTTP_METHODS` object.
68
+
69
+
This change allows for a consistent and clear way to find routes based on the HTTP method.
70
+
71
+
Sedcondly, we've made the `addRoute` method private by prefixing it with a `#`. This means that the `#addRoute` method can now only be accessed from within the `TrieRouter` class and not from outside.
72
+
73
+
Now, to test the new API, let's update our previous example:
Looks good, and now we have a more intuitive way to define routes based on HTTP methods. Let's move on to the next exercise to add support for route parameters.
Copy file name to clipboardExpand all lines: chapters/ch06.9-ex-dynamic-routing.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,4 @@
1
-
## Exercise 4 - Implementing Dynamic Routing
1
+
## Exercise 5 - Implementing Dynamic Routing
2
2
3
3
When we're building a server application, dynamic routing is an essential feature for creating flexible and scalable applications. To fully grasp its significance and how we can enhance our router to support dynamic routes like `/users/:id`, let's delve into the concept of dynamic routing.
0 commit comments