mirror of
https://github.com/sergeyyarkov/node-docker-example.git
synced 2026-10-11 10:19:41 +03:00
refactor: moved logic to multiple files
This commit is contained in:
parent
11e01a24e4
commit
69717ae409
16
db.js
Normal file
16
db.js
Normal 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
18
env.js
Normal 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
15
handlers.js
Normal 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
15
initSchema.js
Normal 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();
|
||||||
@ -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
1
preloads/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
import './routes.js';
|
||||||
8
preloads/routes.js
Normal file
8
preloads/routes.js
Normal 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
29
response.js
Normal 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
30
router.js
Normal 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
130
server.js
@ -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
8
sql/schema_init.sql
Normal 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
|
||||||
|
);
|
||||||
Loading…
x
Reference in New Issue
Block a user