lolo-backend
Version:
Lolo Backend is a REST Framework and provides an automatic asynchronous CRUD backend server generator based on your models' definitions and validation rules for Node.js and MongoDB.
203 lines (168 loc) • 7.86 kB
JavaScript
/*!
* lolo-backend
* Copyright(c) 2021 Camilo Pifano Herrera
* MIT Licensed
*/
//--------------------------------------------------------------------------------------------------------------------//
// BACKEND WEB SERVER:
// This module creates the Backend server (WebServer).
//--------------------------------------------------------------------------------------------------------------------//
module.exports = function() { //Models is a REST parameter.
//Import external modules:
const express = require('express');
const http = require('http');
const https = require('https');
const cors = require('cors');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const moment = require('moment');
const path = require("path");
const fs = require('fs');
//Import services module:
const services = require('./services');
//Define console message separator:
const consoleLn = "|---------------------------------------------------------------------------------------------------------------|";
//Import file settings (YAML):
const settings = services.getFileSettings();
//Set language:
const currentLang = require('./supported_languages')(settings.language);
//Set verbose mode (true or false):
const verboseMode = settings.verbose_log_enabled;
//Import dynamic routes:
const crudRoutes = require('./dynamic_crud');
//Import custom routes:
let customRoutes = '';
if(settings.custom_routes_enabled === true){
customRoutes = require(path.resolve('./', settings.custom_routes_file));
}
//Create express object (app webServer):
const app = express();
//Check if CORS is enabled or disabled:
if(settings.cors_enabled === true){
//Set whitelist (CORS):
let whiteList = [
"http://" + settings.webserver.host + ":" + settings.webserver.http_port,
"https://" + settings.webserver.host + ":" + settings.webserver.https_port
];
//Check settings cors whitelist (not empty):
if(settings.cors_whitelist){
whiteList = whiteList.concat(settings.cors_whitelist);
}
//Set CORS Asynchronously options:
const corsOptionsDelegate = (req, callback) => {
let corsOptions;
if (whiteList.indexOf(req.header('Origin')) !== -1){
corsOptions = { origin: true }; //Reflect (enable) the requested origin in the CORS response.
} else {
corsOptions = { origin: false }; //Disable CORS for this request.
}
callback(null, corsOptions); //Callback expects two parameters: error and options.
}
//Apply CORS options:
app.use(cors(corsOptionsDelegate));
} else {
//Enable All CORS Requests:
app.use(cors());
}
//Configure express Middleware (ex bodyParser):
app.use(express.json()); //Parsing application/json
app.use(express.urlencoded({ extended: true })); //Parsing application/x-www-form-urlencoded
//Parse credentials object to array (necessary for find method):
const arrayCredentials = [];
Object.entries(settings.jwt_credentials).forEach(([key, value]) => {
arrayCredentials.push(value);
});
//Set JWT Login Path:
app.post('/jwt-login', (req, res) => {
//Send console log message:
if(verboseMode === true) { services.sendConsoleMessage(req); }
//Get POST data:
const { username, password } = req.body;
//Filter credential from the credentials array by username and password:
const currentCredential = arrayCredentials.find(credential => { return credential.username === username && credential.password === password });
//Validate existence of result:
if(currentCredential){
//Crear payload:
const payload = {
sub: currentCredential.id, //Identify the subject of the token.
iat: (Date.now() / 1000), //Token creation date.
//exp: (Declared in expiresIn) //Token expiration date.
}
jwt.sign(payload, settings.secret_token, {expiresIn: currentCredential.time_exp}, (err, token) => {
if(err){
res.status(500).send({ success: false, message: currentLang.jwt.sign_error, error: err });
return;
}
res.status(200).send({ success: true, message: currentLang.jwt.sign_success, token: token });
});
} else {
res.status(401).send({ success: false, message: currentLang.jwt.user_pass_error });
}
});
//Set MongoDB URI:
const mongodbURI = 'mongodb://' + settings.db.host + ':' + settings.db.port + '/' + settings.db.name;
//Establish connection with MongoDB:
mongoose.connect(mongodbURI, {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false }, (err) => {
if(err){
console.error('| ' + currentLang.server.db_cnx_error + mongodbURI);
console.log(consoleLn + '\n');
throw err;
} else {
console.log('| ' + currentLang.server.db_cnx_success + mongodbURI);
console.log(consoleLn + '\n');
}
//Verbose mode message:
if(verboseMode === true) {
console.log('Verbose Mode: enabled\n')
} else {
console.log('Verbose Mode: disabled\n')
}
});
//Register paths of custom routes file:
if(settings.custom_routes_enabled === true){
app.use('/', customRoutes);
}
//Generate dynamic CRUD routes based on the specified models:
Object.entries(settings.models).forEach(([key, value]) => {
//Import current model:
const currentModel = require(path.resolve('./', value));
//Set URL path to current model:
app.use('/' + key, crudRoutes(currentModel, currentLang, verboseMode));
});
//Start message:
console.log('\n' + consoleLn);
console.log('| ' + currentLang.server.start + ' | ' + moment().format('DD/MM/YYYY h:mm:ss'));
console.log(consoleLn);
//HTTP Enabled:
if(settings.webserver.http_enabled === true){
//Create HTTP server:
const httpServer = http.createServer(app);
//Start listening on our server:
httpServer.listen(settings.webserver.http_port, () => {
console.log('| http://' + settings.webserver.host + ':' + settings.webserver.http_port);
});
}
//HTTPS Enabled:
if(settings.webserver.https_enabled === true){
const httpsOptions = {
//Reference SSL certificates:
key : fs.readFileSync(path.resolve('./', settings.ssl_certificates.key)),
cert : fs.readFileSync(path.resolve('./', settings.ssl_certificates.cert)),
};
//If certificates is not self-signed:
if(settings.ssl_certificates.ca){
httpsOptions['ca'] = fs.readFileSync(path.resolve('./', settings.ssl_certificates.ca));
}
//Create HTTPS Server:
https.createServer(httpsOptions, app).listen(settings.webserver.https_port, () => {
console.log('| https://' + settings.webserver.host + ':' + settings.webserver.https_port);
});
}
//HTTP and HTTPS Advice:
if(settings.webserver.http_enabled === false && settings.webserver.https_enabled === false ){
console.log('| ' + currentLang.server.non_server);
}
//Export WebServer:
return app;
};
//--------------------------------------------------------------------------------------------------------------------//