Skip to content

Commit

Permalink
refactor: read environment variables with an 'env(key, defaultValue)'…
Browse files Browse the repository at this point in the history
… function

Replace reading environment variables using dot notation with an 'env' function call. Refactor the
database factory code and fix some failing tests
  • Loading branch information
simplymichael committed Jun 26, 2024
1 parent 6fd0a1b commit c2253e9
Show file tree
Hide file tree
Showing 20 changed files with 300 additions and 216 deletions.
32 changes: 16 additions & 16 deletions src/config/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const path = require("node:path");
const env = require("../dotenv");
const env = require("../framework/env");
const is = require("../framework/lib/is");
const string = require("../framework/lib/string");

Expand All @@ -8,9 +8,9 @@ const APP_ROOT = string.convertBackSlashToForwardSlash(path.resolve(path.dirname
const APP_SRC_DIR = `${APP_ROOT}/src`;
const HTTP_REGEX = /^https?:\/\//i;

let host = env.HOST;
let port = env.PORT;
let scheme = env.URL_SCHEME?.toLowerCase();
let host = env("HOST");
let port = env("PORT");
let scheme = env("URL_SCHEME", "http")?.toLowerCase();

if(!(/^https?(:\/\/)?/.test(scheme))) {
scheme = "http://";
Expand All @@ -21,20 +21,20 @@ host = (HTTP_REGEX.test(host)) ? host: `${scheme}${host}`;
port = [80, 443].includes(Number(port)) ? "" : port;

module.exports = {
name : env.NAME,
host : env.HOST,
port : env.PORT,
name : env("NAME"),
host : env("HOST"),
port : env("PORT"),
url : port ? `${host}:${port}` : host,
urlScheme : scheme,
environment : (env.NODE_ENV || "production").toLowerCase(),
apiVersion : env.API_VERSION,
debug : is.falsy(env.DEBUG?.trim()?.toLowerCase()) ? false : true,
timezone : (env.TIMEZONE || "UTC").toUpperCase(),
environment : env("NODE_ENV", "production").toLowerCase(),
apiVersion : env("API_VERSION"),
debug : is.falsy(env("DEBUG").toLowerCase()) ? false : true,
timezone : env("TIMEZONE", "UTC").toUpperCase(),
rootDir : APP_ROOT,
srcDir : APP_SRC_DIR,
viewsDir : `${APP_SRC_DIR}/${(env.VIEWS_DIR || "views")}`,
allowedHeaders : env.ALLOWED_HEADERS.split(SPLIT_REGEX).map(s => s.trim()),
allowedMethods : env.ALLOWED_METHODS.split(SPLIT_REGEX).map(o => o.trim().toUpperCase()),
allowedOrigins : env.ALLOWED_ORIGINS.split(SPLIT_REGEX).map(o => o.trim()),
viewTemplatesEngine: env.VIEW_TEMPLATES_ENGINE,
viewsDir : `${APP_SRC_DIR}/${env("VIEWS_DIR", "views")}`,
allowedHeaders : env("ALLOWED_HEADERS").split(SPLIT_REGEX).map(s => s.trim()),
allowedMethods : env("ALLOWED_METHODS").split(SPLIT_REGEX).map(o => o.trim().toUpperCase()),
allowedOrigins : env("ALLOWED_ORIGINS").split(SPLIT_REGEX).map(o => o.trim()),
viewTemplatesEngine: env("VIEW_TEMPLATES_ENGINE"),
};
8 changes: 4 additions & 4 deletions src/config/cache.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const env = require("../dotenv");
const env = require("../framework/env");
const is = require("../framework/lib/is");
const NodeCache = require( "node-cache" );

Expand All @@ -13,7 +13,7 @@ module.exports = {
* for running a cache operation inside the application
* unless another is explicitly specified during the operation.
*/
default: env.CACHE_STORE || "memory",
default: env("CACHE_STORE", "memory"),

/*
* ----------------
Expand All @@ -24,12 +24,12 @@ module.exports = {
* there might be other applications using the same cache. For
* To avoid collisions, you may prefix every cache key.
*/
prefix: env.CACHE_KEY_PREFIX || `${env.NAME.toLowerCase().replace(/[\s*,-]+/g, "_")}_cache_`,
prefix: env("CACHE_KEY_PREFIX", `${env("NAME").toLowerCase().replace(/[\s*,-]+/g, "_")}_cache_`),

/*
* Whether to compress the data prior to caching.
*/
compress: is.falsy(env.CACHE_COMPRESS_DATA?.trim()?.toLowerCase()) ? false : true,
compress: is.falsy(env("CACHE_COMPRESS_DATA")?.toLowerCase()) ? false : true,

/*
* -------------
Expand Down
4 changes: 2 additions & 2 deletions src/config/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const defaultDbConfig = {
mongodb: {
url : "",
host : "0.0.0.0",
port : 27017,
port : "27017",
username : "",
password : "",
dbName : "",
Expand All @@ -18,7 +18,7 @@ const defaultDbConfig = {
mysql: {
url : "",
host : "0.0.0.0",
port : 27017,
port : "27017",
username : "",
password : "",
dbName : "",
Expand Down
28 changes: 14 additions & 14 deletions src/config/database.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const env = require("../dotenv");
const env = require("../framework/env");

module.exports = {
/*
Expand All @@ -10,7 +10,7 @@ module.exports = {
* This connection will be used unless another connection
* is explicitly specified when you execute a query.
*/
default: (env.DB_CONNECTION.toLowerCase()) || "mongodb",
default: env("DB_CONNECTION", "mongodb").toLowerCase(),

/*
* ---------------------
Expand All @@ -24,22 +24,22 @@ module.exports = {
*/
connections: {
mongodb: {
url : env.DB_URL,
host : env.DB_HOST,
port : Number(env.DB_PORT) || 27017,
username : env.DB_USERNAME,
password : env.DB_PASSWORD,
dbName : env.DB_DBNAME,
url : env("DB_URL"),
host : env("DB_HOST"),
port : env("DB_PORT", 27017),
username : env("DB_USERNAME"),
password : env("DB_PASSWORD"),
dbName : env("DB_DBNAME"),
exitOnConnectFail: true,
},

mysql: {
url : env.DB_URL,
host : env.DB_HOST,
port : Number(env.DB_PORT) || 3006,
username : env.DB_USERNAME,
password : env.DB_PASSWORD,
dbName : env.DB_DBNAME,
url : env("DB_URL"),
host : env("DB_HOST"),
port : env("DB_PORT", 3006),
username : env("DB_USERNAME"),
password : env("DB_PASSWORD"),
dbName : env("DB_DBNAME"),
dbEngine : "mysql",
},
},
Expand Down
4 changes: 2 additions & 2 deletions src/config/logtail.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const env = require("../dotenv");
const env = require("../framework/env");

module.exports = {
sourceToken: env.LOGTAIL_SOURCE_TOKEN,
sourceToken: env("LOGTAIL_SOURCE_TOKEN"),
};
14 changes: 7 additions & 7 deletions src/config/redis.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const env = require("../dotenv");
const env = require("../framework/env");

module.exports = {
url : env.REDIS_URL,
host : env.REDIS_HOST,
port : env.REDIS_PORT,
username : env.REDIS_USERNAME,
password : env.REDIS_PASSWORD,
db : env.REDIS_DATABASE || "0",
url : env("REDIS_URL"),
host : env("REDIS_HOST", "localhost"),
port : env("REDIS_PORT", 6379),
username : env("REDIS_USERNAME", "default"),
password : env("REDIS_PASSWORD"),
db : env("REDIS_DATABASE", "0"),
autoConnect : true,
};
18 changes: 9 additions & 9 deletions src/config/session.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const env = require("../dotenv");
const env = require("../framework/env");
const is = require("../framework/lib/is");

module.exports = {
name : env.SESSION_NAME,
cookieDomain : env.SESSION_COOKIE_DOMAIN,
cookiePath : env.SESSION_COOKIE_PATH,
expiry : 1000 * 60 * (Number(env.SESSION_EXPIRY) || 15),
secret : env.SESSION_SECRET,
secure : is.falsy(env.SESSION_SECURE?.toLowerCase()) ? false : true,
sameSite : env.SESSION_SAME_SITE,
storageDriver : (env.SESSION_STORE_DRIVER || "memory").toLowerCase(),
name : env("SESSION_NAME", "connect.sid"),
cookieDomain : env("SESSION_COOKIE_DOMAIN"),
cookiePath : env("SESSION_COOKIE_PATH", "/"),
expiry : 1000 * 60 * Number(env("SESSION_EXPIRY", 15)),
secret : env("SESSION_SECRET"),
secure : is.falsy(env("SESSION_SECURE").toLowerCase()) ? false : true,
sameSite : env("SESSION_SAME_SITE"),
storageDriver : env("SESSION_STORE_DRIVER", "memory").toLowerCase(),
};
5 changes: 0 additions & 5 deletions src/dotenv.js

This file was deleted.

3 changes: 3 additions & 0 deletions src/framework/app-root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const APP_ROOT = require("app-root-path");

module.exports = APP_ROOT;
143 changes: 0 additions & 143 deletions src/framework/application/app/app.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,137 +34,6 @@ const httpMethods = [
"unsubscribe"
];

const HTTP_STATUS_CODES = {
HTTP_CONTINUE: 100,
HTTP_SWITCHING_PROTOCOLS: 101,
HTTP_PROCESSING: 102,
HTTP_EARLY_HINTS: 103,
HTTP_OK: 200,
HTTP_CREATED: 201,
HTTP_ACCEPTED: 202,
HTTP_NON_AUTHORITATIVE_INFORMATION: 203,
HTTP_NO_CONTENT: 204,
HTTP_RESET_CONTENT: 205,
HTTP_PARTIAL_CONTENT: 206,
HTTP_MULTI_STATUS: 207,
HTTP_ALREADY_REPORTED: 208,
HTTP_IM_USED: 226,
HTTP_MULTIPLE_CHOICES: 300,
HTTP_MOVED_PERMANENTLY: 301,
HTTP_FOUND: 302,
HTTP_SEE_OTHER: 303,
HTTP_NOT_MODIFIED: 304,
HTTP_USE_PROXY: 305,
HTTP_RESERVED: 306,
HTTP_TEMPORARY_REDIRECT: 307,
HTTP_PERMANENTLY_REDIRECT: 308,
HTTP_BAD_REQUEST: 400,
HTTP_UNAUTHORIZED: 401,
HTTP_PAYMENT_REQUIRED: 402,
HTTP_FORBIDDEN: 403,
HTTP_NOT_FOUND: 404,
HTTP_METHOD_NOT_ALLOWED: 405,
HTTP_NOT_ACCEPTABLE: 406,
HTTP_PROXY_AUTHENTICATION_REQUIRED: 407,
HTTP_REQUEST_TIMEOUT: 408,
HTTP_CONFLICT: 409,
HTTP_GONE: 410,
HTTP_LENGTH_REQUIRED: 411,
HTTP_PRECONDITION_FAILED: 412,
HTTP_REQUEST_ENTITY_TOO_LARGE: 413,
HTTP_REQUEST_URI_TOO_LONG: 414,
HTTP_UNSUPPORTED_MEDIA_TYPE: 415,
HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: 416,
HTTP_EXPECTATION_FAILED: 417,
HTTP_I_AM_A_TEAPOT: 418,
HTTP_MISDIRECTED_REQUEST: 421,
HTTP_UNPROCESSABLE_ENTITY: 422,
HTTP_LOCKED: 423,
HTTP_FAILED_DEPENDENCY: 424,
HTTP_TOO_EARLY: 425,
HTTP_UPGRADE_REQUIRED: 426,
HTTP_PRECONDITION_REQUIRED: 428,
HTTP_TOO_MANY_REQUESTS: 429,
HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: 451,
HTTP_INTERNAL_SERVER_ERROR: 500,
HTTP_NOT_IMPLEMENTED: 501,
HTTP_BAD_GATEWAY: 502,
HTTP_SERVICE_UNAVAILABLE: 503,
HTTP_GATEWAY_TIMEOUT: 504,
HTTP_VERSION_NOT_SUPPORTED: 505,
HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL: 506,
HTTP_INSUFFICIENT_STORAGE: 507,
HTTP_LOOP_DETECTED: 508,
HTTP_NOT_EXTENDED: 510,
HTTP_NETWORK_AUTHENTICATION_REQUIRED: 511,
};

const HTTP_STATUS_TEXTS = [
[100, "Continue"],
[101, "Switching Protocols"],
[102, "Processing"],
[103, "Early Hints"],
[200, "OK"],
[201, "Created"],
[202, "Accepted"],
[203, "Non-Authoritative Information"],
[204, "No Content"],
[205, "Reset Content"],
[206, "Partial Content"],
[207, "Multi-Status"],
[208, "Already Reported"],
[226, "IM Used"],
[300, "Multiple Choices"],
[301, "Moved Permanently"],
[302, "Found"],
[303, "See Other"],
[304, "Not Modified"],
[305, "Use Proxy"],
[307, "Temporary Redirect"],
[308, "Permanent Redirect"],
[400, "Bad Request"],
[401, "Unauthorized"],
[402, "Payment Required"],
[403, "Forbidden"],
[404, "Not Found"],
[405, "Method Not Allowed"],
[406, "Not Acceptable"],
[407, "Proxy Authentication Required"],
[408, "Request Timeout"],
[409, "Conflict"],
[410, "Gone"],
[411, "Length Required"],
[412, "Precondition Failed"],
[413, "Content Too Large"],
[414, "URI Too Long"],
[415, "Unsupported Media Type"],
[416, "Range Not Satisfiable"],
[417, "Expectation Failed"],
[418 , "I'm a teapot"],
[421, "Misdirected Request"],
[422, "Unprocessable Content"],
[423, "Locked"],
[424, "Failed Dependency"],
[425, "Too Early"],
[426, "Upgrade Required"],
[428, "Precondition Required"],
[429, "Too Many Requests"],
[431, "Request Header Fields Too Large"],
[451, "Unavailable For Legal Reasons"],
[500, "Internal Server Error"],
[501, "Not Implemented"],
[502, "Bad Gateway"],
[503, "Service Unavailable"],
[504, "Gateway Timeout"],
[505, "HTTP Version Not Supported"],
[506, "Variant Also Negotiates"],
[507, "Insufficient Storage"],
[508, "Loop Detected"],
[510, "Not Extended"],
[511, "Network Authentication Required"],
];


/*
* Assert the options injected into (web and api) route groups by the app.
Expand All @@ -174,8 +43,6 @@ function assertRouteGroupOptions(options) {
expect(options).to.have.property("router").to.be.an("object");
expect(options).to.have.property("download").to.be.a("function");
expect(options).to.have.property("view").to.be.a("function");
expect(options).to.have.property("STATUS_CODES").to.be.an("object");
expect(options).to.have.property("STATUS_TEXTS").to.be.an("object");

for(const method of routerMethods) {
expect(options.router).to.have.property(method).to.be.a("function");
Expand All @@ -184,16 +51,6 @@ function assertRouteGroupOptions(options) {
for(const verb of httpMethods) {
expect(typeof options.router[verb]).to.equal("function");
}

for(const [key, value] of Object.entries(HTTP_STATUS_CODES)) {
expect(options.STATUS_CODES).to.have.property(key, value);
}

for(const element of HTTP_STATUS_TEXTS) {
const [key, value] = element;

expect(options.STATUS_TEXTS).to.have.property(key, value);
}
}

module.exports = {
Expand Down
2 changes: 1 addition & 1 deletion src/framework/application/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const APP_ROOT = require("app-root-path");
const APP_ROOT = require("../app-root");
const SRC_DIR = `${APP_ROOT}/src`.replace(/\\/g, "/");

const { createApp, normalizePort, onError, onListening } = require("./app");
Expand Down
4 changes: 2 additions & 2 deletions src/framework/application/server/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env node, mocha */

const request = require("supertest");
const { StatusCodes, StatusTexts } = require("../../component/http");
const { STATUS_CODES, STATUS_TEXTS } = require("../../component/http");
const { chai } = require("../../lib/test-helper");
const config = require("../test-mocks/config");
const webRouter = require("../test-mocks/routes/web");
Expand Down Expand Up @@ -171,7 +171,7 @@ module.exports = {

expect(res.body).to.be.an("object");
expect(res.body).to.have.property("success", true);
expect(res.body).to.have.property("message", StatusTexts[StatusCodes.HTTP_OK]);
expect(res.body).to.have.property("message", STATUS_TEXTS[STATUS_CODES.HTTP_OK]);
done();
});
});
Expand Down
Loading

0 comments on commit c2253e9

Please sign in to comment.