refactor: moved logic to multiple files

This commit is contained in:
Sergey Yarkov 2022-03-15 20:39:33 +03:00
parent 11e01a24e4
commit 69717ae409
11 changed files with 170 additions and 103 deletions

16
db.js Normal file
View File

@ -0,0 +1,16 @@
import pg from 'pg';
import env from './env.js';
class Database {
constructor() {
this.client = new pg.Client({
user: env.db.user,
host: env.db.host,
database: env.db.name,
password: env.db.password,
port: env.db.port,
});
}
}
export default new Database();

18
env.js Normal file
View File

@ -0,0 +1,18 @@
import dotenv from 'dotenv';
dotenv.config({ path: process.cwd() + '/.env' });
const env = {
app: {
port: parseInt(process.env.PORT, 10),
},
db: {
user: process.env.PG_USER.toString(),
host: process.env.PG_HOST.toString(),
name: process.env.PG_DB_NAME.toString(),
password: process.env.PG_PASSWORD.toString(),
port: parseInt(process.env.PG_PORT, 10),
},
};
export default env;

15
handlers.js Normal file
View File

@ -0,0 +1,15 @@
import http from 'node:http';
import Response from './response.js';
/**
* Get list of all artcles from database
*
* @param {http.ClientRequest} req
* @param {Response} res
*/
export const getArticlesHandler = async (req, res) => {
res.json([
{ id: 1, title: 'First artcile' },
{ id: 2, title: 'Second artcile' },
]);
};

15
initSchema.js Normal file
View File

@ -0,0 +1,15 @@
import fs from 'node:fs';
import db from './db.js';
async function run() {
const { client } = db;
client.connect();
const query = fs.readFileSync('sql/schema_init.sql').toString();
await client.query(query);
console.log(`SQL: ${query}`);
await client.end();
}
await run();

View File

@ -2,10 +2,11 @@
"name": "node-docker-example", "name": "node-docker-example",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "server.js",
"type": "module", "type": "module",
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",
"db:init": "node initSchema.js",
"dev": "nodemon server.js" "dev": "nodemon server.js"
}, },
"keywords": [ "keywords": [

1
preloads/index.js Normal file
View File

@ -0,0 +1 @@
import './routes.js';

8
preloads/routes.js Normal file
View File

@ -0,0 +1,8 @@
import router from '../router.js';
/**
* Handlers
*/
import { getArticlesHandler } from '../handlers.js';
router.define('/api/articles', getArticlesHandler);

29
response.js Normal file
View File

@ -0,0 +1,29 @@
import http from 'node:http';
class Response {
/**
* Extends the http response object with this class
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
*/
constructor(req, res) {
this.req = req;
this.res = res;
}
send(text) {
this.res.writeHead(200, { 'Content-Type': 'text/plain' });
this.res.end(text);
}
json(data, status = 200) {
this.res.writeHead(status, { 'Content-Type': 'application/json' });
this.res.end(JSON.stringify(data));
}
notFound(data) {
this.json(data, 404);
}
}
export default Response;

30
router.js Normal file
View File

@ -0,0 +1,30 @@
import http from 'node:http';
class Router {
constructor() {
/**
* Store the current list of routes for out API
*/
this.routes = {};
}
/**
*
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
* @returns
*/
call(req, res) {
if (this.routes.hasOwnProperty(req.url)) {
this.routes[req.url](req, res);
return true;
}
return false;
}
define(url, handler) {
this.routes[url] = handler;
}
}
export default new Router();

130
server.js
View File

@ -1,95 +1,26 @@
import http from 'node:http'; import http from 'node:http';
import dotenv from 'dotenv'; import env from './env.js';
import pg from 'pg'; import db from './db.js';
import router from './router.js';
class Database { import Response from './response.js';
constructor() { import './preloads/index.js';
this.client = new pg.Client({
user: process.env.PG_USER,
host: process.env.PG_HOST,
database: process.env.PG_DB_NAME,
password: process.env.PG_PASSWORD,
port: process.env.PG_PORT,
});
}
}
class Router {
constructor() {
/**
* Store the current list of routes for out API
*/
this.routes = {};
}
/**
*
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
* @returns
*/
call(req, res) {
if (this.routes.hasOwnProperty(req.url)) {
this.routes[req.url](req, res);
return true;
}
return false;
}
define(url, handler) {
this.routes[url] = handler;
}
}
class Response {
#req;
#res;
/**
* Extends the http response object with this class
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
*/
constructor(req, res) {
this.#req = req;
this.#res = res;
}
send(text) {
this.#res.writeHead(200, { 'Content-Type': 'text/plain' });
this.#res.end(text);
}
json(data, status = 200) {
this.#res.writeHead(status, { 'Content-Type': 'application/json' });
this.#res.end(JSON.stringify(data));
}
notFound(data) {
this.json(data, 404);
}
}
class Application { class Application {
constructor() { constructor() {
this.booted = false; this.booted = false;
this.config = this.#setupConfig();
this.server = http.createServer(); this.server = http.createServer();
this.db = new Database(); this.router = router;
this.router = new Router(); this.db = db;
this.#connectDb(this.db.client).then(() => this.run());
} }
run() { async run() {
this.#handle(); try {
this.booted = true; await this.#connectDb(this.db.client);
} this.#handle();
this.booted = true;
#setupConfig() { } catch (error) {
return { throw new Error(error);
config: dotenv.config(), }
};
} }
/** /**
@ -97,11 +28,10 @@ class Application {
* @param {pg.Client} client * @param {pg.Client} client
*/ */
async #connectDb(client) { async #connectDb(client) {
try { await client.connect().catch((error) => {
await client.connect();
} catch (error) {
console.error(error); console.error(error);
} throw new Error(error);
});
} }
#handle() { #handle() {
@ -127,24 +57,20 @@ class Application {
*/ */
response.send('Static Page.'); response.send('Static Page.');
}); });
this.server.listen(process.env.PORT, () => this.server.listen(env.app.port, () =>
console.log(`Server is running on port "${process.env.PORT}"`) console.log(`[LOG]: Server is running on port "${env.app.port}"`)
); );
} }
} }
const app = new Application(); const app = new Application();
/** app.run().catch((error) => {
* console.error('[ERR]: Error on startup the application.', error);
* @param {http.ClientRequest} req });
* @param {Response} res
*/
const getArticlesHandler = async (req, res) => {
res.json([
{ id: 1, title: 'First artcile' },
{ id: 2, title: 'Second artcile' },
]);
};
app.router.define('/api/articles', getArticlesHandler); process.on('SIGINT', () => {
console.log(`[LOG]: Graceefully stopping the server...`);
app.server.close();
process.exit();
});

8
sql/schema_init.sql Normal file
View File

@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS "articles"(
"id" INTEGER PRIMARY KEY NOT NULL,
"title" VARCHAR(255) NOT NULL,
"description" VARCHAR(255) NOT NULL,
"body" TEXT NOT NULL,
"created_at" TIMESTAMP(0) WITH TIME zone NOT NULL,
"updated_at" TIMESTAMP(0) WITH TIME zone NOT NULL
);