mirror of
https://github.com/sergeyyarkov/node-docker-example.git
synced 2026-10-11 02:09:22 +03:00
feat: added new article handler & route handling by regexp
This commit is contained in:
parent
69717ae409
commit
e17386a782
35
handlers.js
35
handlers.js
@ -1,5 +1,6 @@
|
||||
import http from 'node:http';
|
||||
import Response from './response.js';
|
||||
import db from './db.js';
|
||||
|
||||
/**
|
||||
* Get list of all artcles from database
|
||||
@ -8,8 +9,34 @@ import Response from './response.js';
|
||||
* @param {Response} res
|
||||
*/
|
||||
export const getArticlesHandler = async (req, res) => {
|
||||
res.json([
|
||||
{ id: 1, title: 'First artcile' },
|
||||
{ id: 2, title: 'Second artcile' },
|
||||
]);
|
||||
const data = await db.client.query('SELECT * FROM "articles"');
|
||||
res.json({ data: data.rows });
|
||||
};
|
||||
|
||||
/**
|
||||
* Get article by ID
|
||||
*
|
||||
* @param {http.ClientRequest} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
export const getArticleHandler = async (req, res) => {
|
||||
/**
|
||||
* Validate url `id` param
|
||||
*/
|
||||
if (!/^\d+$/.test(req.params.id)) {
|
||||
res.json({ data: {}, error: 'Parameters is not valid!' }, 422);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await db.client.query(
|
||||
'SELECT * from "articles" WHERE "id" = $1',
|
||||
[req.params.id]
|
||||
);
|
||||
|
||||
if (data.rows.length === 0) {
|
||||
res.json({ data: {}, error: 'Article not found.' }, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ data: data.rows });
|
||||
};
|
||||
|
||||
41
package-lock.json
generated
41
package-lock.json
generated
@ -393,6 +393,18 @@
|
||||
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.7.7",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.0",
|
||||
"source-map": "^0.6.1",
|
||||
"uglify-js": "^3.1.4",
|
||||
"wordwrap": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
@ -594,8 +606,7 @@
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
@ -603,6 +614,11 @@
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"neo-async": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
|
||||
},
|
||||
"nodemon": {
|
||||
"version": "2.0.15",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz",
|
||||
@ -682,6 +698,11 @@
|
||||
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
|
||||
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.0.tgz",
|
||||
"integrity": "sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg=="
|
||||
},
|
||||
"pg": {
|
||||
"version": "8.7.3",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz",
|
||||
@ -881,6 +902,11 @@
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"split2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
|
||||
@ -960,6 +986,12 @@
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.15.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.3.tgz",
|
||||
"integrity": "sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg==",
|
||||
"optional": true
|
||||
},
|
||||
"undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
@ -1026,6 +1058,11 @@
|
||||
"string-width": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"pg": "^8.7.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import router from '../router.js';
|
||||
/**
|
||||
* Handlers
|
||||
*/
|
||||
import { getArticlesHandler } from '../handlers.js';
|
||||
import { getArticleHandler, getArticlesHandler } from '../handlers.js';
|
||||
|
||||
router.define('/api/articles', getArticlesHandler);
|
||||
router.define('/api/article/:id', getArticleHandler);
|
||||
|
||||
@ -11,8 +11,8 @@ class Response {
|
||||
this.res = res;
|
||||
}
|
||||
|
||||
send(text) {
|
||||
this.res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
send(text, status = 200) {
|
||||
this.res.writeHead(status, { 'Content-Type': 'text/plain' });
|
||||
this.res.end(text);
|
||||
}
|
||||
|
||||
@ -21,8 +21,8 @@ class Response {
|
||||
this.res.end(JSON.stringify(data));
|
||||
}
|
||||
|
||||
notFound(data) {
|
||||
this.json(data, 404);
|
||||
notFound(text) {
|
||||
this.send(text, 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
56
router.js
56
router.js
@ -1,29 +1,77 @@
|
||||
import http from 'node:http';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
|
||||
class Router {
|
||||
constructor() {
|
||||
/**
|
||||
* Store the current list of routes for out API
|
||||
* Store the current list of routes
|
||||
*/
|
||||
this.routes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks for the existence of a route and calls its handler
|
||||
*
|
||||
* @param {http.ClientRequest} req
|
||||
* @param {http.ServerResponse} res
|
||||
* @returns
|
||||
*/
|
||||
call(req, res) {
|
||||
/**
|
||||
* Find the exact route
|
||||
*/
|
||||
if (this.routes.hasOwnProperty(req.url)) {
|
||||
this.routes[req.url](req, res);
|
||||
this.routes[req.url].handler(req, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find route by regular expression
|
||||
*/
|
||||
const keys = Object.keys(this.routes);
|
||||
let i = keys.length;
|
||||
|
||||
while (i--) {
|
||||
const route = this.routes[keys[i]];
|
||||
if (!route.options.exact && route.options.regexp !== undefined) {
|
||||
const match = req.url.match(route.options.regexp);
|
||||
if (match) {
|
||||
if (route.options.params !== undefined) {
|
||||
req.params = {};
|
||||
route.options.params.forEach((param) => {
|
||||
req.params[param.name] = match[1];
|
||||
});
|
||||
}
|
||||
route.handler(req, res);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
define(url, handler) {
|
||||
this.routes[url] = handler;
|
||||
/**
|
||||
* Add more routes to router store
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {function} handler
|
||||
* @param {boolean} exact
|
||||
*/
|
||||
define(
|
||||
url,
|
||||
handler,
|
||||
options = { exact: true, regexp: undefined, params: undefined }
|
||||
) {
|
||||
if (url.includes(':')) {
|
||||
options.params = [];
|
||||
options.exact = false;
|
||||
options.regexp = pathToRegexp(url, options.params);
|
||||
}
|
||||
this.routes[url] = {
|
||||
handler,
|
||||
options,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user