diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..02bb8abf --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +NODE_ENV=development +PORT=4040 +JWT_SECRET=0a6b944d-d2fb-46fc-a85e-0295c986cd9f +MONGO_HOST=mongodb://localhost/express-mongoose-es6-rest-api-development +MONGO_PORT=27017 diff --git a/.gitignore b/.gitignore index f1956130..d70e27f4 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ node_modules # Optional REPL history .node_repl_history + +# .env +.env diff --git a/.istanbul.yml b/.istanbul.yml index deb39607..b67186b0 100644 --- a/.istanbul.yml +++ b/.istanbul.yml @@ -1,6 +1,6 @@ verbose: false instrumentation: - excludes: ['dist/**', 'coverage/**', 'gulpfile.babel.js', 'config/env/development.js', 'config/env/production.js'] + excludes: ['dist/**', 'coverage/**', 'gulpfile.babel.js'] include-all-sources: true reporting: print: summary @@ -22,4 +22,4 @@ check: statements: 50 lines: 50 branches: 30 - functions: 20 \ No newline at end of file + functions: 20 diff --git a/config/config.js b/config/config.js new file mode 100644 index 00000000..3ca2c9ff --- /dev/null +++ b/config/config.js @@ -0,0 +1,44 @@ +import Joi from 'joi'; + +// require and configure dotenv, will load vars in .env in PROCESS.ENV +require('dotenv').config(); + +// define validation for all the env vars +const envVarsSchema = Joi.object({ + NODE_ENV: Joi.string() + .allow(['development', 'production', 'test', 'provision']) + .default('development'), + PORT: Joi.number() + .default(4040), + MONGOOSE_DEBUG: Joi.boolean() + .when('NODE_ENV', { + is: Joi.string().equal('development'), + then: Joi.boolean().default(true), + otherwise: Joi.boolean().default(false) + }), + JWT_SECRET: Joi.string().required() + .description('JWT Secret required to sign'), + MONGO_HOST: Joi.string().required() + .description('Mongo DB host url'), + MONGO_PORT: Joi.number() + .default(27017) +}).unknown() + .required(); + +const { error, value: envVars } = Joi.validate(process.env, envVarsSchema); +if (error) { + throw new Error(`Config validation error: ${error.message}`); +} + +const config = { + env: envVars.NODE_ENV, + port: envVars.PORT, + mongooseDebug: envVars.MONGOOSE_DEBUG, + jwtSecret: envVars.JWT_SECRET, + mongo: { + host: envVars.MONGO_HOST, + port: envVars.MONGO_PORT + } +}; + +export default config; diff --git a/config/env/development.js b/config/env/development.js deleted file mode 100644 index f9f95e98..00000000 --- a/config/env/development.js +++ /dev/null @@ -1,9 +0,0 @@ -const devConfig = { - env: 'development', - MONGOOSE_DEBUG: true, - jwtSecret: '0a6b944d-d2fb-46fc-a85e-0295c986cd9f', - db: 'mongodb://localhost/express-mongoose-es6-rest-api-development', - port: 4040 -}; - -export default devConfig; diff --git a/config/env/index.js b/config/env/index.js deleted file mode 100644 index 6d9e0812..00000000 --- a/config/env/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import path from 'path'; - -const env = process.env.NODE_ENV || 'development'; -const config = require(`./${env}`); // eslint-disable-line import/no-dynamic-require - -const defaults = { - root: path.join(__dirname, '/..') -}; - -export default Object.assign(defaults, config); diff --git a/config/env/production.js b/config/env/production.js deleted file mode 100644 index 879cad6b..00000000 --- a/config/env/production.js +++ /dev/null @@ -1,8 +0,0 @@ -const prodConfig = { - env: 'production', - jwtSecret: '0a6b944d-d2fb-46fc-a85e-0295c986cd9f', - db: 'mongodb://localhost/express-mongoose-es6-rest-api-production', - port: 4040 -}; - -export default prodConfig; diff --git a/config/env/test.js b/config/env/test.js deleted file mode 100644 index f168c4e9..00000000 --- a/config/env/test.js +++ /dev/null @@ -1,8 +0,0 @@ -const testConfig = { - env: 'test', - jwtSecret: '0a6b944d-d2fb-46fc-a85e-0295c986cd9f', - db: 'mongodb://localhost/express-mongoose-es6-rest-api-test', - port: 4040 -}; - -export default testConfig; diff --git a/config/express.js b/config/express.js index 3d058ada..555d3a63 100644 --- a/config/express.js +++ b/config/express.js @@ -11,7 +11,7 @@ import expressValidation from 'express-validation'; import helmet from 'helmet'; import winstonInstance from './winston'; import routes from '../server/routes/index.route'; -import config from './env'; +import config from './config'; import APIError from '../server/helpers/APIError'; const app = express(); diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 2e40ddb4..53155cb3 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -8,13 +8,13 @@ const plugins = gulpLoadPlugins(); const paths = { js: ['./**/*.js', '!dist/**', '!node_modules/**', '!coverage/**'], - nonJs: ['./package.json', './.gitignore'], + nonJs: ['./package.json', './.gitignore', './.env'], tests: './server/tests/*.js' }; // Clean up dist and coverage directory gulp.task('clean', () => - del.sync(['dist/**', 'coverage/**', '!dist', '!coverage']) + del.sync(['dist/**', 'dist/.*', 'coverage/**', '!dist', '!coverage']) ); // Copy non-js files to dist diff --git a/index.js b/index.js index f56c7d42..7bd9ba17 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,8 @@ import mongoose from 'mongoose'; import util from 'util'; -import config from './config/env'; + +// config should be imported before importing any other file +import config from './config/config'; import app from './config/express'; const debug = require('debug')('express-mongoose-es6-rest-api:index'); @@ -12,7 +14,8 @@ Promise = require('bluebird'); // eslint-disable-line no-global-assign mongoose.Promise = Promise; // connect to mongo db -mongoose.connect(config.db, { server: { socketOptions: { keepAlive: 1 } } }); +const mongoUri = `${config.mongo.host}:${config.mongo.port}`; +mongoose.connect(mongoUri, { server: { socketOptions: { keepAlive: 1 } } }); mongoose.connection.on('error', () => { throw new Error(`unable to connect to database: ${config.db}`); }); diff --git a/package.json b/package.json index ec94fa02..1444a8d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "express-mongoose-es6-rest-api", - "version": "1.0.0", + "version": "2.0.0", "description": "A Boilerplate application for building REST APIs using express, mongoose in ES6 with code coverage", "author": "Kunal Kapadia ", "main": "index.js", @@ -47,6 +47,7 @@ "cookie-parser": "1.4.3", "cors": "2.8.1", "debug": "^2.4.5", + "dotenv": "^4.0.0", "express": "4.14.0", "express-jwt": "5.1.0", "express-validation": "1.0.1", diff --git a/server/controllers/auth.controller.js b/server/controllers/auth.controller.js index 2ea47632..f8403e76 100644 --- a/server/controllers/auth.controller.js +++ b/server/controllers/auth.controller.js @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken'; import httpStatus from 'http-status'; import APIError from '../helpers/APIError'; -import config from '../../config/env'; +import config from '../../config/config'; // sample user, used for authentication const user = { diff --git a/server/routes/auth.route.js b/server/routes/auth.route.js index cdf37b63..6ccf23a2 100644 --- a/server/routes/auth.route.js +++ b/server/routes/auth.route.js @@ -3,7 +3,7 @@ import validate from 'express-validation'; import expressJwt from 'express-jwt'; import paramValidation from '../../config/param-validation'; import authCtrl from '../controllers/auth.controller'; -import config from '../../config/env'; +import config from '../../config/config'; const router = express.Router(); // eslint-disable-line new-cap diff --git a/server/tests/auth.test.js b/server/tests/auth.test.js index 9b781d99..f2711021 100644 --- a/server/tests/auth.test.js +++ b/server/tests/auth.test.js @@ -3,7 +3,7 @@ import httpStatus from 'http-status'; import jwt from 'jsonwebtoken'; import chai, { expect } from 'chai'; import app from '../../index'; -import config from '../../config/env'; +import config from '../../config/config'; chai.config.includeStack = true; diff --git a/yarn.lock b/yarn.lock index f79019a0..9c67e441 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1397,6 +1397,10 @@ dont-sniff-mimetype@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" +dotenv@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d" + duplexer2@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"