Boilerplates, base config, folder structure, utils, etc.

This commit is contained in:
Kaushik 2022-10-07 14:25:50 +05:30
parent dbcb4afce0
commit 76b6f05e92
11 changed files with 236 additions and 1 deletions

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Dependency directories
node_modules/
# dotenv environment variables file
.env.development
.env.production
*.env
# Data files
*/*.csv

6
.sequelizerc Normal file
View File

@ -0,0 +1,6 @@
require("dotenv-flow").config();
const path = require("path");
module.exports = {
"config": path.resolve("config", "config.js")
};

View File

@ -1,2 +1 @@
# Induction app back-end # Induction app back-end

View File

@ -0,0 +1,19 @@
const typedefs = require("../typedefs");
const logger = require("../utils/logger")(module);
/**
* @param {typedefs.Req} req
* @param {typedefs.Res} res
*/
const __controller_func = async (req, res) => {
try {
} catch (error) {
logger.error("Error", { error });
return res.status(500).send({ message: "Server Error. Try again." });
}
}
module.exports = {
__controller_func
};

13
boilerplates/route.js Normal file
View File

@ -0,0 +1,13 @@
const router = require("express").Router();
const { validate } = require("../validators");
router.get(
);
router.post(
);
module.exports = router;

22
boilerplates/validator.js Normal file
View File

@ -0,0 +1,22 @@
const { body, header, param, query } = require("express-validator");
const typedefs = require("../typedefs");
/**
* @param {typedefs.Req} req
* @param {typedefs.Res} res
* @param {typedefs.Next} next
*/
const __validator_func = async (req, res, next) => {
await body("field_name")
.notEmpty()
.withMessage("field_name not defined in body")
.run(req);
next();
}
module.exports = {
__validator_func,
}

16
config/config.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
"development": {
"username": process.env.DB_USERNAME, // local PostgreSQL DB username
"password": process.env.DB_PASSWORD, // local PostgreSQL DB password
"host": "127.0.0.1", // localhost
"database": process.env.DB_NAME, // local PostgreSQL DB name
"dialect": "postgres"
},
"production": {
"use_env_variable": "DB_URL", // production database connection string
"dialect": "postgres",
"dialectOptions": {
"ssl": true,
},
}
}

40
models/index.js Normal file
View File

@ -0,0 +1,40 @@
"use strict";
const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || "development";
const config = require(__dirname + "/../config/config.js")[env];
const db = {};
// Create new Sequelize instance
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
// Read model definitions from folder
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf(".") !== 0) && (file !== basename) && (file.slice(-3) === ".js");
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
// Setup defined associations
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;

15
typedefs.js Normal file
View File

@ -0,0 +1,15 @@
/**
* @typedef {import("module")} Module
*
* @typedef {import("express").Request} Req
* @typedef {import("express").Response} Res
* @typedef {import("express").NextFunction} Next
*
* @typedef {import("sequelize") Sequelize}
* @typedef {import("sequelize").Model Model}
* @typedef {import("sequelize").QueryInterface QueryInterface}
*
* @typedef {import("winston").Logger} Logger
*/
exports.unused = {};

59
utils/logger.js Normal file
View File

@ -0,0 +1,59 @@
const path = require("path");
const { createLogger, transports, config, format } = require("winston");
const { combine, label, timestamp, printf } = format;
const typedefs = require("../typedefs");
const getLabel = (callingModule) => {
const parts = callingModule.filename.split(path.sep);
return path.join(parts[parts.length - 2], parts.pop());
};
const logMetaReplacer = (key, value) => {
if (key === "error") {
return value.name + ": " + value.message;
}
return value;
}
const metaFormat = (meta) => {
if (Object.keys(meta).length > 0)
return "\n" + JSON.stringify(meta, logMetaReplacer) + "\n";
return "\n";
}
const logFormat = printf(({ level, message, label, timestamp, ...meta }) => {
if (meta.error) {
for (const key in meta.error) {
if (typeof key !== "symbol" && key !== "message" && key !== "name") {
delete meta.error[key]
}
}
}
return `${timestamp} [${label}] ${level}: ${message}${metaFormat(meta)}`;
});
/**
* Creates a curried function, and call it with the module in use to get logs with filename
* @param {typedefs.Module} callingModule The module from which the logger is called
* @returns {typedefs.Logger}
*/
const logger = (callingModule) => {
return createLogger({
levels: config.npm.levels,
format: combine(
label({ label: getLabel(callingModule) }),
timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
logFormat,
),
transports: [
process.env.NODE_ENV !== "production" ?
new transports.Console() :
new transports.File({ filename: __dirname + "/../logs/common.log" }),
new transports.File({ filename: __dirname + "/../logs/error.log", level: "error" }),
]
});
}
module.exports = logger;

28
validators/index.js Normal file
View File

@ -0,0 +1,28 @@
const { validationResult } = require("express-validator");
const typedefs = require("../typedefs");
/**
* Middleware to call after running validators to finalize result
* @param {typedefs.Req} req
* @param {typedefs.Res} res
* @param {typedefs.Next} next
*/
const validate = (req, res, next) => {
const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}
const extractedErrors = []
errors.array().map(err => extractedErrors.push({
[err.param]: err.msg
}));
return res.status(400).json({
message: extractedErrors,
})
}
module.exports = {
validate,
}