slower 2.1.8 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +386 -0
- package/examples/router.js +45 -0
- package/examples/subrouter.js +29 -0
- package/examples/third-party-middlewares.js +88 -0
- package/package.json +11 -15
- package/src/decorators.js +3 -7
- package/src/slower.js +167 -134
- package/src/utils.js +52 -32
- package/readme.md.old +0 -180
package/src/slower.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
const http = require('node:http');
|
|
3
2
|
const https = require('node:https');
|
|
4
3
|
const path = require('node:path');
|
|
@@ -6,8 +5,6 @@ const fs = require('node:fs');
|
|
|
6
5
|
const { createReadStream } = require('node:fs');
|
|
7
6
|
const { pipeline } = require('node:stream/promises');
|
|
8
7
|
|
|
9
|
-
const { match } = require('path-to-regexp');
|
|
10
|
-
|
|
11
8
|
const { setupRequest, setupResponse } = require('./decorators');
|
|
12
9
|
const utils = require('./utils');
|
|
13
10
|
|
|
@@ -20,16 +17,16 @@ class SlowerRouter {
|
|
|
20
17
|
|
|
21
18
|
// You can create it with HTTPS options here
|
|
22
19
|
/**
|
|
23
|
-
* Use HTTPS server instead of HTTP.
|
|
20
|
+
* Use HTTPS server instead of HTTP.
|
|
24
21
|
* Pass in all regular HTTPS options as parameters.
|
|
25
22
|
* 'key' and 'cert' options are required for HTTPS.
|
|
26
|
-
* @param {object} options
|
|
23
|
+
* @param {object} options
|
|
27
24
|
* @returns {http.Server|https.Server}
|
|
28
25
|
* @example
|
|
29
26
|
* SlowerRouter({https:true, key:'...', cert:'...'}); // Create HTTPS server
|
|
30
27
|
* SlowerRouter(); // Create regular HTTP
|
|
31
28
|
*/
|
|
32
|
-
constructor
|
|
29
|
+
constructor(options = {}) {
|
|
33
30
|
this.METHODS = HTTP_VERBS;
|
|
34
31
|
this.layers = new Map();
|
|
35
32
|
|
|
@@ -42,7 +39,7 @@ class SlowerRouter {
|
|
|
42
39
|
* or
|
|
43
40
|
* app.get({handler}) -> apply handlers for any route for a specific method
|
|
44
41
|
* app.get({handler}, {handler}, ...) -> apply handlers for any route for a specific method
|
|
45
|
-
*
|
|
42
|
+
*
|
|
46
43
|
*/
|
|
47
44
|
for (let verb of HTTP_VERBS) {
|
|
48
45
|
this.layers.set(verb, new Map());
|
|
@@ -55,22 +52,24 @@ class SlowerRouter {
|
|
|
55
52
|
};
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
if (options.https)
|
|
59
|
-
|
|
60
|
-
else
|
|
61
|
-
this.#server = http.createServer(options);
|
|
55
|
+
if (options.https) this.#server = https.createServer(options);
|
|
56
|
+
else this.#server = http.createServer(options);
|
|
62
57
|
|
|
63
58
|
this.#server.on('request', this.#requestHandlerWrapper(this));
|
|
64
59
|
}
|
|
65
|
-
|
|
66
|
-
#requestHandlerWrapper
|
|
60
|
+
|
|
61
|
+
#requestHandlerWrapper() {
|
|
67
62
|
// Save the 'this' scope
|
|
68
63
|
// Inside the requestHandler function, 'this' corresponds to the http.Server instance
|
|
69
64
|
const self = this;
|
|
70
65
|
|
|
71
|
-
return
|
|
66
|
+
return async function requestHandler(req, res) {
|
|
72
67
|
// Get all routes that match the URL and join with middlewares to cycle
|
|
73
|
-
let foundRoutes = utils.getMatchingRoute(
|
|
68
|
+
let foundRoutes = utils.getMatchingRoute(
|
|
69
|
+
req.url,
|
|
70
|
+
req.method,
|
|
71
|
+
self.layers
|
|
72
|
+
);
|
|
74
73
|
let layers = foundRoutes;
|
|
75
74
|
// Add an Error:404 special layer to the end of the layers list
|
|
76
75
|
// This prevents accidental requests hanging
|
|
@@ -78,34 +77,47 @@ class SlowerRouter {
|
|
|
78
77
|
|
|
79
78
|
// Set properties on request and response objects
|
|
80
79
|
req = await setupRequest(req);
|
|
81
|
-
res = await setupResponse(res);
|
|
80
|
+
res = await setupResponse(res, req);
|
|
82
81
|
|
|
83
82
|
// Cycle throught all middlewares and proper routes and call with 'next()' as third argument
|
|
84
|
-
|
|
83
|
+
(async function cycleMatching(routes) {
|
|
85
84
|
if (routes.length === 0) return;
|
|
86
85
|
let route = routes[0];
|
|
87
86
|
if (route.params) req.params = route.params;
|
|
88
87
|
if (route.callback) route = route.callback;
|
|
89
88
|
route(req, res, async () => cycleMatching(routes.slice(1)));
|
|
90
89
|
})(layers);
|
|
91
|
-
}
|
|
90
|
+
};
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
listen
|
|
95
|
-
|
|
93
|
+
listen(...v) {
|
|
94
|
+
return this.#server.listen(...v);
|
|
95
|
+
}
|
|
96
|
+
close(callback) {
|
|
97
|
+
return this.#server.close(callback);
|
|
98
|
+
}
|
|
96
99
|
|
|
97
100
|
// Add any type of route
|
|
98
|
-
#setRoute
|
|
99
|
-
if (typeof method !== 'string')
|
|
100
|
-
throw new Error(
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
#setRoute(method, path, handler) {
|
|
102
|
+
if (typeof method !== 'string')
|
|
103
|
+
throw new Error(
|
|
104
|
+
'<SlowerRouter>.route :: "method" parameter must be of type String'
|
|
105
|
+
);
|
|
106
|
+
if (
|
|
107
|
+
typeof path !== 'string' &&
|
|
108
|
+
typeof path !== 'function' &&
|
|
109
|
+
path?.constructor?.name !== 'RegExp'
|
|
110
|
+
)
|
|
111
|
+
throw new Error(
|
|
112
|
+
'<SlowerRouter>.route :: "path" parameter must be of type Function, String or RegExp'
|
|
113
|
+
);
|
|
103
114
|
if (typeof handler !== 'function')
|
|
104
|
-
throw new Error(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
115
|
+
throw new Error(
|
|
116
|
+
'<SlowerRouter>.route :: "handler" parameter must be of type Function'
|
|
117
|
+
);
|
|
118
|
+
if (!this.layers.get(method)) this.layers.set(method, new Map());
|
|
119
|
+
if (typeof path === 'string' || path?.constructor?.name !== 'RegExp')
|
|
120
|
+
path = utils.buildURLPatternFunction(path); // 'path' is a function now
|
|
109
121
|
this.layers.get(method).set(path, handler);
|
|
110
122
|
return this;
|
|
111
123
|
}
|
|
@@ -114,7 +126,7 @@ class SlowerRouter {
|
|
|
114
126
|
/**
|
|
115
127
|
* Create a middleware for all HTTP methods, for a specific path
|
|
116
128
|
* @overload
|
|
117
|
-
* @param {String} path
|
|
129
|
+
* @param {String} path
|
|
118
130
|
* @param {...Function} handlers
|
|
119
131
|
* @returns {SlowerRouter}
|
|
120
132
|
* @example Applies a middleware for all methods, for a specific path
|
|
@@ -123,7 +135,7 @@ class SlowerRouter {
|
|
|
123
135
|
/**
|
|
124
136
|
* Create a global middleware for a specific verb (all paths for that method)
|
|
125
137
|
* @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
|
|
126
|
-
* @overload
|
|
138
|
+
* @overload
|
|
127
139
|
* @param {string} verb (one of the HTTP verbs)
|
|
128
140
|
* @param {...Function} handlers
|
|
129
141
|
* @returns {SlowerRouter}
|
|
@@ -132,44 +144,44 @@ class SlowerRouter {
|
|
|
132
144
|
*/
|
|
133
145
|
/**
|
|
134
146
|
* Create a global middleware (all paths and all HTTP methods)
|
|
135
|
-
* @overload
|
|
136
|
-
* @param {...Function} handlers
|
|
147
|
+
* @overload
|
|
148
|
+
* @param {...Function} handlers
|
|
137
149
|
* @returns {SlowerRouter}
|
|
138
150
|
* @example Applies a middleware for all HTTP requests (of any method)
|
|
139
151
|
* app.all((req, res, next) => {console.log(...); next()})
|
|
140
152
|
*/
|
|
141
|
-
all
|
|
142
|
-
|
|
153
|
+
all(path, ...handlers) {
|
|
143
154
|
// function signature: app.all({METHOD}, ...{HANDLERS})
|
|
144
155
|
// example: app.all('post', () => {});
|
|
145
156
|
if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
|
|
146
157
|
for (let handler of handlers)
|
|
147
158
|
this.#setRoute(path, MATCH_ANY, handler);
|
|
148
|
-
|
|
149
|
-
|
|
150
159
|
// function signature: app.all({PATH}, ...{HANDLERS})
|
|
151
160
|
// example: app.all('/api', () => {});
|
|
152
161
|
else if (typeof path === 'string')
|
|
153
162
|
for (let handler of handlers)
|
|
154
|
-
for (let verb of HTTP_VERBS)
|
|
163
|
+
for (let verb of HTTP_VERBS)
|
|
155
164
|
this.#setRoute(verb, path, handler);
|
|
156
|
-
|
|
157
165
|
// function signature: app.all(...{HANDLERS})
|
|
158
|
-
// example: app.all(() => {});
|
|
166
|
+
// example: app.all(() => {});
|
|
159
167
|
else if (typeof path === 'function')
|
|
160
168
|
for (let verb of HTTP_VERBS) {
|
|
161
169
|
this.#setRoute(verb, MATCH_ANY, path);
|
|
162
170
|
for (let handler of handlers)
|
|
163
171
|
this.#setRoute(verb, MATCH_ANY, handler);
|
|
164
172
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
else
|
|
174
|
+
throw new Error(
|
|
175
|
+
'<SlowerRouter>.use :: "handler" parameter must be of type Function'
|
|
176
|
+
);
|
|
168
177
|
|
|
169
178
|
return this;
|
|
170
179
|
}
|
|
171
180
|
// Just a more comprehensive call to app.all for defining middlewares
|
|
172
|
-
use
|
|
181
|
+
use(...b) {
|
|
182
|
+
this.all(...b);
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
173
185
|
|
|
174
186
|
/**
|
|
175
187
|
* Serve static files from a directory
|
|
@@ -179,33 +191,46 @@ class SlowerRouter {
|
|
|
179
191
|
* @example
|
|
180
192
|
* // Using a mounting poing:
|
|
181
193
|
* app.static('./public', '/files') // Access with 'GET /files/{filename}'
|
|
182
|
-
*
|
|
194
|
+
*
|
|
183
195
|
* // Not using a mounting point:
|
|
184
196
|
* app.static('./public') // Access with 'GET /public/{filename}'
|
|
185
|
-
*
|
|
197
|
+
*
|
|
186
198
|
* // Using root ('/') as mounting point:
|
|
187
199
|
* app.static('./public', '/') // Access with 'GET /{filename}'
|
|
188
200
|
*/
|
|
189
|
-
static
|
|
201
|
+
static(directoryPath, mountPath = '') {
|
|
190
202
|
const absoluteDir = path.resolve(directoryPath);
|
|
191
203
|
if (!fs.existsSync(absoluteDir))
|
|
192
|
-
throw new Error(
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Invalid directory provided for [SlowerRouter].static(): [${directoryPath}]`
|
|
206
|
+
);
|
|
193
207
|
|
|
194
208
|
for (const file of utils.getFiles(absoluteDir)) {
|
|
195
209
|
// Get only the file name from the absolute file path 'c:\u\a.txt' -> 'a.txt'
|
|
196
|
-
let fileAsURLPath = file
|
|
210
|
+
let fileAsURLPath = file
|
|
211
|
+
.replaceAll(/\\/g, '/')
|
|
212
|
+
.split('/')
|
|
213
|
+
.slice(-1)[0];
|
|
197
214
|
// If there is a mount path, merge it with the file and remove duplicate bars '//'
|
|
198
|
-
if (!mountPath)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
215
|
+
if (!mountPath)
|
|
216
|
+
mountPath = directoryPath
|
|
217
|
+
.replaceAll(/\\/g, '/')
|
|
218
|
+
.split('/')
|
|
219
|
+
.slice(-1)[0];
|
|
220
|
+
fileAsURLPath = ('/' + mountPath + '/' + fileAsURLPath).replaceAll(
|
|
221
|
+
/\/+/g,
|
|
222
|
+
'/'
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
async function staticfhandle(req, res /*next*/) {
|
|
203
226
|
try {
|
|
204
227
|
const fileStream = createReadStream(file);
|
|
205
|
-
res.setHeader(
|
|
228
|
+
res.setHeader(
|
|
229
|
+
'Content-Type',
|
|
230
|
+
MIME_TABLE[extension] || MIME_TABLE['default']
|
|
231
|
+
);
|
|
206
232
|
return await pipeline(fileStream, res);
|
|
207
|
-
|
|
208
|
-
} catch (err) {
|
|
233
|
+
} catch {
|
|
209
234
|
// In case the file does not exist, return a 404 and prevent it from breaking
|
|
210
235
|
res.status(404).end();
|
|
211
236
|
}
|
|
@@ -216,7 +241,7 @@ class SlowerRouter {
|
|
|
216
241
|
// If the file is an html file, also add a path for using it without the '.html' extension
|
|
217
242
|
// both 'GET /files/somefile.html' and 'GET /files/somefile' would work
|
|
218
243
|
const extension = utils.getFileExtension(file);
|
|
219
|
-
if (extension === 'html')
|
|
244
|
+
if (extension === 'html')
|
|
220
245
|
this.get(fileAsURLPath.replace('.html', ''), staticfhandle);
|
|
221
246
|
}
|
|
222
247
|
return this;
|
|
@@ -225,13 +250,14 @@ class SlowerRouter {
|
|
|
225
250
|
/**
|
|
226
251
|
* Import and use another SlowerRouter, mounted at a specific path
|
|
227
252
|
* @param {string} mountPath Mount the router at a specific path
|
|
228
|
-
* @param {SlowerRouter} SlowerRouterInstance
|
|
253
|
+
* @param {SlowerRouter} SlowerRouterInstance
|
|
229
254
|
*/
|
|
230
|
-
useRouter
|
|
231
|
-
const mount = p =>
|
|
255
|
+
useRouter(SlowerSubRouterInstance, mountPath = '/') {
|
|
256
|
+
const mount = p =>
|
|
257
|
+
mountPath ? (mountPath + '/' + p).replace(/\/{2,}/g, '/') : p;
|
|
232
258
|
const layers = SlowerSubRouterInstance.layers;
|
|
233
259
|
for (let layer of layers) {
|
|
234
|
-
if (
|
|
260
|
+
if (layer.static) {
|
|
235
261
|
this.static(layer.directoryPath, mount(layer.mountPath));
|
|
236
262
|
continue;
|
|
237
263
|
}
|
|
@@ -243,38 +269,36 @@ class SlowerRouter {
|
|
|
243
269
|
/**
|
|
244
270
|
* Creates a temporary synced mini-router for a specific path
|
|
245
271
|
* Allows to declare multiple handlers for methods of a specific path
|
|
246
|
-
* @param {string} path
|
|
272
|
+
* @param {string} path
|
|
247
273
|
* @returns {SlowerMicroRouter}
|
|
248
|
-
* @example
|
|
274
|
+
* @example
|
|
249
275
|
* app.route('/books')
|
|
250
276
|
* .get((req, res) => console.log('you retrieved a book with GET'))
|
|
251
277
|
* .post((req, res) => console.log('you added a book with POST'))
|
|
252
278
|
* ;
|
|
253
279
|
*/
|
|
254
|
-
route
|
|
280
|
+
route(path) {
|
|
255
281
|
return new SlowerMicroRouter(path, this.layers);
|
|
256
282
|
}
|
|
257
283
|
}
|
|
258
284
|
|
|
259
|
-
|
|
260
285
|
/**
|
|
261
286
|
* Used as the class for modular routers
|
|
262
287
|
* used in "slower.Router()"
|
|
263
288
|
*/
|
|
264
289
|
class SlowerSubRouter {
|
|
265
|
-
constructor
|
|
290
|
+
constructor() {
|
|
266
291
|
this.METHODS = HTTP_VERBS;
|
|
267
292
|
this.layers = new Array();
|
|
268
293
|
|
|
269
294
|
// OLD version: (Do not delete until new version is properly tested)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
295
|
+
// Create basic route shortcuts
|
|
296
|
+
// get(), post(), put(), delete()
|
|
297
|
+
// for (let verb of HTTP_VERBS) {
|
|
298
|
+
// this[verb] = function (path, callback) {
|
|
299
|
+
// return this.#setRoute(verb, path, callback);
|
|
300
|
+
// };
|
|
301
|
+
// }
|
|
278
302
|
|
|
279
303
|
// Create basic route shortcuts
|
|
280
304
|
// get(), post(), put(), delete(), ...
|
|
@@ -285,7 +309,7 @@ class SlowerSubRouter {
|
|
|
285
309
|
* or
|
|
286
310
|
* app.get({handler}) -> apply handlers for any route for a specific method
|
|
287
311
|
* app.get({handler}, {handler}, ...) -> apply handlers for any route for a specific method
|
|
288
|
-
*
|
|
312
|
+
*
|
|
289
313
|
*/
|
|
290
314
|
for (let verb of HTTP_VERBS) {
|
|
291
315
|
this[verb] = function (path, ...callbacks) {
|
|
@@ -298,13 +322,19 @@ class SlowerSubRouter {
|
|
|
298
322
|
}
|
|
299
323
|
}
|
|
300
324
|
|
|
301
|
-
#setRoute
|
|
302
|
-
if (typeof method !== 'string')
|
|
303
|
-
throw new Error(
|
|
325
|
+
#setRoute(method, path, handler) {
|
|
326
|
+
if (typeof method !== 'string')
|
|
327
|
+
throw new Error(
|
|
328
|
+
'<SlowerSubRouter>.route :: "method" parameter must be of type String'
|
|
329
|
+
);
|
|
304
330
|
if (typeof path !== 'string' && path?.constructor?.name !== 'RegExp')
|
|
305
|
-
throw new Error(
|
|
331
|
+
throw new Error(
|
|
332
|
+
'<SlowerSubRouter>.route :: "path" parameter must be of type Function, String or RegExp'
|
|
333
|
+
);
|
|
306
334
|
if (typeof handler !== 'function')
|
|
307
|
-
throw new Error(
|
|
335
|
+
throw new Error(
|
|
336
|
+
'<SlowerSubRouter>.route :: "handler" parameter must be of type Function'
|
|
337
|
+
);
|
|
308
338
|
this.layers.push({ method, path, handler });
|
|
309
339
|
return this;
|
|
310
340
|
}
|
|
@@ -313,8 +343,8 @@ class SlowerSubRouter {
|
|
|
313
343
|
/**
|
|
314
344
|
* Create a middleware for all HTTP methods, for a specific path
|
|
315
345
|
* @overload
|
|
316
|
-
* @param {String} path
|
|
317
|
-
* @param {...Function} handlers
|
|
346
|
+
* @param {String} path
|
|
347
|
+
* @param {...Function} handlers
|
|
318
348
|
* @returns {SlowerRouter}
|
|
319
349
|
* @example Applies a middleware for all methods, for a specific path
|
|
320
350
|
* app.all('/img/:id', (req, res, next) => {console.log(...); next()})
|
|
@@ -322,7 +352,7 @@ class SlowerSubRouter {
|
|
|
322
352
|
/**
|
|
323
353
|
* Create a global middleware for a specific verb (all paths for that method)
|
|
324
354
|
* @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
|
|
325
|
-
* @overload
|
|
355
|
+
* @overload
|
|
326
356
|
* @param {string} verb (one of the HTTP verbs)
|
|
327
357
|
* @param {...Function} handlers
|
|
328
358
|
* @returns {SlowerRouter}
|
|
@@ -331,46 +361,46 @@ class SlowerSubRouter {
|
|
|
331
361
|
*/
|
|
332
362
|
/**
|
|
333
363
|
* Create a global middleware (all paths and all HTTP methods)
|
|
334
|
-
* @overload
|
|
364
|
+
* @overload
|
|
335
365
|
* @param {...Function} handlers
|
|
336
366
|
* @returns {SlowerRouter}
|
|
337
367
|
* @example Applies a middleware for all HTTP requests (of any method)
|
|
338
368
|
* app.all((req, res, next) => {console.log(...); next()})
|
|
339
369
|
*/
|
|
340
|
-
all
|
|
341
|
-
|
|
370
|
+
all(path, ...handlers) {
|
|
342
371
|
// function signature: app.all({METHOD}, ...{HANDLERS})
|
|
343
372
|
// example: app.all('post', () => {});
|
|
344
373
|
if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
|
|
345
374
|
for (let handler of handlers)
|
|
346
375
|
this.#setRoute(path, MATCH_ANY, handler);
|
|
347
|
-
|
|
348
|
-
|
|
349
376
|
// function signature: app.all({PATH}, ...{HANDLERS})
|
|
350
377
|
// example: app.all('/api', () => {});
|
|
351
378
|
else if (typeof path === 'string')
|
|
352
379
|
for (let handler of handlers)
|
|
353
|
-
for (let verb of HTTP_VERBS)
|
|
380
|
+
for (let verb of HTTP_VERBS)
|
|
354
381
|
this.#setRoute(verb, path, handler);
|
|
355
|
-
|
|
356
382
|
// function signature: app.all(...{HANDLERS})
|
|
357
|
-
// example: app.all(() => {});
|
|
383
|
+
// example: app.all(() => {});
|
|
358
384
|
else if (typeof path === 'function')
|
|
359
385
|
for (let verb of HTTP_VERBS) {
|
|
360
386
|
this.#setRoute(verb, MATCH_ANY, path);
|
|
361
387
|
for (let handler of handlers)
|
|
362
388
|
this.#setRoute(verb, MATCH_ANY, handler);
|
|
363
389
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
390
|
+
else
|
|
391
|
+
throw new Error(
|
|
392
|
+
'<SlowerSubRouter>.use :: "handler" parameter must be of type Function'
|
|
393
|
+
);
|
|
367
394
|
|
|
368
395
|
return this;
|
|
369
396
|
}
|
|
370
397
|
// Just a more comprehensive call to app.all for defining middlewares
|
|
371
|
-
use
|
|
398
|
+
use(...b) {
|
|
399
|
+
this.all(...b);
|
|
400
|
+
return this;
|
|
401
|
+
}
|
|
372
402
|
|
|
373
|
-
static
|
|
403
|
+
static(directoryPath, mountPath = '') {
|
|
374
404
|
this.layers.push({ static: true, directoryPath, mountPath });
|
|
375
405
|
return this;
|
|
376
406
|
}
|
|
@@ -378,31 +408,29 @@ class SlowerSubRouter {
|
|
|
378
408
|
/**
|
|
379
409
|
* Creates a temporary synced mini-router for a specific path
|
|
380
410
|
* Allows to declare multiple handlers for methods of a specific path
|
|
381
|
-
* @param {string} path
|
|
411
|
+
* @param {string} path
|
|
382
412
|
* @returns {SlowerMicroRouter}
|
|
383
|
-
* @example
|
|
413
|
+
* @example
|
|
384
414
|
* app.route('/books')
|
|
385
415
|
* .get((req, res) => console.log('you retrieved a book with GET'))
|
|
386
416
|
* .post((req, res) => console.log('you added a book with POST'))
|
|
387
417
|
* ;
|
|
388
418
|
*/
|
|
389
|
-
route
|
|
419
|
+
route(path) {
|
|
390
420
|
return new SlowerMicroRouter(path, this.layers);
|
|
391
421
|
}
|
|
392
422
|
}
|
|
393
423
|
|
|
394
|
-
|
|
395
|
-
|
|
396
424
|
/**
|
|
397
425
|
* Used as the class for micro-routing with "app.route"
|
|
398
|
-
*
|
|
426
|
+
*
|
|
399
427
|
* only method acessors (.get(), .post(), .put(), ...)
|
|
400
428
|
* and .all() and .use()
|
|
401
|
-
*
|
|
429
|
+
*
|
|
402
430
|
* .static() is not allowed
|
|
403
431
|
*/
|
|
404
432
|
class SlowerMicroRouter {
|
|
405
|
-
constructor
|
|
433
|
+
constructor(path, layerPool) {
|
|
406
434
|
this.path = path;
|
|
407
435
|
this.layers = layerPool;
|
|
408
436
|
|
|
@@ -410,21 +438,26 @@ class SlowerMicroRouter {
|
|
|
410
438
|
// get(), post(), put(), delete()
|
|
411
439
|
for (let verb of HTTP_VERBS) {
|
|
412
440
|
this[verb] = function (...callbacks) {
|
|
413
|
-
for (let callback of callbacks)
|
|
414
|
-
|
|
415
|
-
return this;
|
|
441
|
+
for (let callback of callbacks) this.#setRoute(verb, callback);
|
|
442
|
+
return this;
|
|
416
443
|
};
|
|
417
444
|
}
|
|
418
445
|
}
|
|
419
446
|
|
|
420
|
-
#setRoute
|
|
447
|
+
#setRoute(method, handler) {
|
|
421
448
|
const path = this.path;
|
|
422
|
-
if (typeof method !== 'string')
|
|
423
|
-
throw new Error(
|
|
449
|
+
if (typeof method !== 'string')
|
|
450
|
+
throw new Error(
|
|
451
|
+
'<SlowerMicroRouter>.route :: "method" parameter must be of type String'
|
|
452
|
+
);
|
|
424
453
|
if (typeof path !== 'string' && path?.constructor?.name !== 'RegExp')
|
|
425
|
-
throw new Error(
|
|
454
|
+
throw new Error(
|
|
455
|
+
'<SlowerMicroRouter>.route :: "path" parameter must be of type Function, String or RegExp'
|
|
456
|
+
);
|
|
426
457
|
if (typeof handler !== 'function')
|
|
427
|
-
throw new Error(
|
|
458
|
+
throw new Error(
|
|
459
|
+
'<SlowerMicroRouter>.route :: "handler" parameter must be of type Function'
|
|
460
|
+
);
|
|
428
461
|
this.layers.push({ method, path, handler });
|
|
429
462
|
return this;
|
|
430
463
|
}
|
|
@@ -433,8 +466,8 @@ class SlowerMicroRouter {
|
|
|
433
466
|
/**
|
|
434
467
|
* Create a middleware for all HTTP methods, for a specific path
|
|
435
468
|
* @overload
|
|
436
|
-
* @param {String} path
|
|
437
|
-
* @param {...Function} handlers
|
|
469
|
+
* @param {String} path
|
|
470
|
+
* @param {...Function} handlers
|
|
438
471
|
* @returns {SlowerRouter}
|
|
439
472
|
* @example Applies a middleware for all methods, for a specific path
|
|
440
473
|
* app.all('/img/:id', (req, res, next) => {console.log(...); next()})
|
|
@@ -442,63 +475,63 @@ class SlowerMicroRouter {
|
|
|
442
475
|
/**
|
|
443
476
|
* Create a global middleware for a specific verb (all paths for that method)
|
|
444
477
|
* @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
|
|
445
|
-
* @overload
|
|
478
|
+
* @overload
|
|
446
479
|
* @param {string} verb (one of the HTTP verbs)
|
|
447
|
-
* @param {...Function} handlers
|
|
480
|
+
* @param {...Function} handlers
|
|
448
481
|
* @returns {SlowerRouter}
|
|
449
482
|
* @example Applies a middleware for all GET requests
|
|
450
483
|
* app.all('get', (req, res, next) => {console.log(...); next()})
|
|
451
484
|
*/
|
|
452
485
|
/**
|
|
453
486
|
* Create a global middleware (all paths and all HTTP methods)
|
|
454
|
-
* @overload
|
|
455
|
-
* @param {...Function} handlers
|
|
487
|
+
* @overload
|
|
488
|
+
* @param {...Function} handlers
|
|
456
489
|
* @returns {SlowerRouter}
|
|
457
490
|
* @example Applies a middleware for all HTTP requests (of any method)
|
|
458
491
|
* app.all((req, res, next) => {console.log(...); next()})
|
|
459
492
|
*/
|
|
460
|
-
all
|
|
461
|
-
|
|
493
|
+
all(path, ...handlers) {
|
|
462
494
|
// function signature: app.all({METHOD}, ...{HANDLERS})
|
|
463
495
|
// example: app.all('post', () => {});
|
|
464
496
|
if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
|
|
465
497
|
for (let handler of handlers)
|
|
466
498
|
this.#setRoute(path, MATCH_ANY, handler);
|
|
467
|
-
|
|
468
|
-
|
|
469
499
|
// function signature: app.all({PATH}, ...{HANDLERS})
|
|
470
500
|
// example: app.all('/api', () => {});
|
|
471
501
|
else if (typeof path === 'string')
|
|
472
502
|
for (let handler of handlers)
|
|
473
|
-
for (let verb of HTTP_VERBS)
|
|
503
|
+
for (let verb of HTTP_VERBS)
|
|
474
504
|
this.#setRoute(verb, path, handler);
|
|
475
|
-
|
|
476
505
|
// function signature: app.all(...{HANDLERS})
|
|
477
|
-
// example: app.all(() => {});
|
|
506
|
+
// example: app.all(() => {});
|
|
478
507
|
else if (typeof path === 'function')
|
|
479
508
|
for (let verb of HTTP_VERBS) {
|
|
480
509
|
this.#setRoute(verb, MATCH_ANY, path);
|
|
481
510
|
for (let handler of handlers)
|
|
482
511
|
this.#setRoute(verb, MATCH_ANY, handler);
|
|
483
512
|
}
|
|
513
|
+
else
|
|
514
|
+
throw new Error(
|
|
515
|
+
'<SlowerMicroRouter>.use :: "handler" parameter must be of type Function'
|
|
516
|
+
);
|
|
484
517
|
|
|
485
|
-
|
|
486
|
-
else throw new Error('<SlowerMicroRouter>.use :: "handler" parameter must be of type Function');
|
|
487
|
-
|
|
488
518
|
return this;
|
|
489
519
|
}
|
|
490
520
|
// Just a more comprehensive call to app.all for defining middlewares
|
|
491
|
-
use
|
|
521
|
+
use(...b) {
|
|
522
|
+
this.all(...b);
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
492
525
|
}
|
|
493
526
|
|
|
494
|
-
|
|
495
527
|
// Create basic main routing creation
|
|
496
|
-
function slower
|
|
528
|
+
function slower(options) {
|
|
497
529
|
return new SlowerRouter(options);
|
|
498
530
|
}
|
|
531
|
+
|
|
499
532
|
// Add the subrouter class
|
|
500
533
|
slower.Router = function () {
|
|
501
534
|
return new SlowerSubRouter();
|
|
502
|
-
}
|
|
535
|
+
};
|
|
503
536
|
|
|
504
537
|
module.exports = slower;
|