feat: added middlewares

This commit is contained in:
Sergey Yarkov 2022-03-16 19:59:17 +03:00
parent 93c72e36a8
commit ac9248bf7f
4 changed files with 116 additions and 27 deletions

12
helpers/string.js Normal file
View File

@ -0,0 +1,12 @@
class StringHelper {
/**
* Delete the trailing slash from url
*
* @param {string} url
*/
static delTrailingSlash(url) {
return url.slice(-1) === '/' ? url.slice(0, -1) : url;
}
}
export default StringHelper;

13
middlewares.js Normal file
View File

@ -0,0 +1,13 @@
import http from 'node:http';
import Response from './response.js';
/**
* This middleware just prints text to console
*
* @param {http.ClientRequest} req
* @param {Response} res
* @param {function} next
*/
export const helloMiddleware = (req, res) => {
console.log('[LOG]: Hello from `helloMiddleware` function');
};

View File

@ -9,6 +9,11 @@ import {
getArticlesHandler,
} from '../handlers.js';
router.define('GET', '/api/articles', getArticlesHandler);
router.define('GET', '/api/article/:id', getArticleHandler);
router.define('POST', '/api/article', createArticleHandler);
/**
* Middlewares
*/
import { helloMiddleware } from '../middlewares.js';
router.get('/api/articles', getArticlesHandler).middleware([helloMiddleware]);
router.get('/api/article/:id', getArticleHandler).middleware([helloMiddleware]);
router.post('/api/article', createArticleHandler);

107
router.js
View File

@ -1,5 +1,6 @@
import http from 'node:http';
import { pathToRegexp } from 'path-to-regexp';
import StringHelper from './helpers/string.js';
class Router {
constructor() {
@ -17,24 +18,28 @@ class Router {
* @returns {boolean} Is route has been handled
*/
call(req, res) {
const mask = `${req.method}:${req.url}`;
/**
* Find the exact route
*/
if (this.routes.hasOwnProperty(mask)) {
this.routes[mask].handler(req, res);
return true;
}
/**
* Find route by regular expression
*/
const mask = `${req.method}:${StringHelper.delTrailingSlash(req.url)}`;
const keys = Object.keys(this.routes);
let i = keys.length;
while (i--) {
const route = this.routes[keys[i]];
let route = this.routes[mask];
/**
* Find exact route
*/
if (this.routes.hasOwnProperty(mask)) {
this.#middlewares(route, req, res);
route.handler(req, res);
return true;
}
/* Route url is not exact */
route = this.routes[keys[i]];
/**
* Find route by regular expression
*/
if (!route.options.exact && route.options.regexp !== undefined) {
const match = req.url.match(route.options.regexp);
if (match && keys[i].includes(req.method)) {
@ -44,6 +49,7 @@ class Router {
req.params[param.name] = match[1];
});
}
this.#middlewares(route, req, res);
route.handler(req, res);
return true;
}
@ -53,29 +59,82 @@ class Router {
return false;
}
/**
* This function will execute every middleware of a route
*
* @param {*} route
* @param {http.ClientRequest} req
* @param {Response} res
* @returns
*/
#middlewares(route, req, res) {
if (!route || !route.middlewares || !Array.isArray(route.middleware)) {
return;
}
const middlewares = route.middlewares.flat();
if (middlewares.length !== 0) {
for (const middleware of middlewares) {
middleware(req, res);
}
}
}
/**
* Add more routes to router store
*
* @param {string} url
* @param {function} handler
* @param {boolean} exact
* @param {string} method HTTP Method
* @param {string} url Route url
* @param {function} handler Route handler function
*/
define(
method = 'GET',
url,
handler,
options = { exact: true, regexp: undefined, params: undefined }
) {
define(method = 'GET', url, handler) {
const mask = `${method}:${StringHelper.delTrailingSlash(url)}`;
const options = { exact: true, regexp: undefined, params: undefined };
if (url.includes(':')) {
options.params = [];
options.exact = false;
options.regexp = pathToRegexp(url, options.params);
}
this.routes[`${method}:${url}`] = {
this.routes[mask] = {
method,
handler,
options,
middlewares: [],
};
return {
/**
* Store the list of middlewares for each router
*
* @param {function | [function]} middleware
*/
middleware: (middleware) => {
middleware = Array.isArray(middleware) ? middleware : [middleware];
this.routes[mask].middlewares.push(middleware);
},
};
}
/**
* GET Method route
*
* @param {string} url
* @param {function} handler
*/
get(url, handler) {
return this.define('GET', url, handler);
}
/**
* POST Method route
*
* @param {string} url
* @param {function} handler
*/
post(url, handler) {
return this.define('POST', url, handler);
}
}