├── .dockerignore ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── Dockerfile.webpack ├── Jenkinsfile ├── README.md ├── apprunner.yaml ├── dist └── api.bundle.js ├── environments ├── .env-dev ├── .env-prod └── .env-test ├── index.js ├── jenkinsfile ├── logger └── logger.js ├── package-lock.json ├── package.json ├── routes ├── routes.js └── user.js ├── webpack-dotenvplugin.config.js ├── webpack-envplugin.config.js └── webpack.config.js /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb-base" 3 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # from base image node 2 | FROM node:8.11-slim 3 | 4 | RUN mkdir -p /usr/src/app 5 | WORKDIR /usr/src/app 6 | 7 | # copying all the files from your file system to container file system 8 | COPY package.json . 9 | 10 | # install all dependencies 11 | RUN npm install 12 | 13 | # copy oter files as well 14 | COPY ./ . 15 | 16 | #expose the port 17 | EXPOSE 3070 18 | 19 | # command to run when intantiate an image 20 | CMD ["npm","start"] 21 | -------------------------------------------------------------------------------- /Dockerfile.webpack: -------------------------------------------------------------------------------- 1 | # from base image node 2 | FROM node:8.11-slim 3 | 4 | RUN mkdir -p /usr/src/app 5 | WORKDIR /usr/src/app 6 | 7 | # copy oter files as well 8 | COPY dist/api.bundle.js . 9 | 10 | #expose the port 11 | EXPOSE 3070 12 | 13 | # command to run when intantiate an image 14 | CMD ["node","api.bundle.js"] -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('install') { 5 | steps { 6 | sh 'npm install' 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # prod-ready-node-rest-api 2 | This is production ready node.js rest api 3 | -------------------------------------------------------------------------------- /apprunner.yaml: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | runtime: nodejs12 3 | build: 4 | commands: 5 | pre-build: 6 | - npm install 7 | build: 8 | - npm run build 9 | run: 10 | runtime-version: 12.18.4 11 | command: npm run prod 12 | network: 13 | port: 3070 14 | env: APP_PORT 15 | -------------------------------------------------------------------------------- /environments/.env-dev: -------------------------------------------------------------------------------- 1 | ENVIRONMENT=development 2 | PORT=3000 3 | GREETING_MESSAGE=API Running In Development Environment 4 | API_WORKS_MESSAGE=Development API Works!!! 5 | DB_USERNAME=dev username 6 | DB_PASSWORD=dev password 7 | DB_CONNECTION_STR=dev connection string -------------------------------------------------------------------------------- /environments/.env-prod: -------------------------------------------------------------------------------- 1 | ENVIRONMENT=production 2 | PORT=3080 3 | GREETING_MESSAGE=API Running In Production Environment 4 | API_WORKS_MESSAGE=Production API Works!!! 5 | DB_USERNAME=prod username 6 | DB_PASSWORD=prod password 7 | DB_CONNECTION_STR=prod connection string -------------------------------------------------------------------------------- /environments/.env-test: -------------------------------------------------------------------------------- 1 | ENVIRONMENT=test 2 | PORT=3080 3 | GREETING_MESSAGE=API Running In Test Environment 4 | API_WORKS_MESSAGE=Test API Works!!! 5 | DB_USERNAME=test username 6 | DB_PASSWORD=test password 7 | DB_CONNECTION_STR=test connection string -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | const express = require('express'); 3 | const bodyParser = require('body-parser'); 4 | const logger = require('./logger/logger'); 5 | 6 | const app = express(); 7 | 8 | const port = process.env.PORT || 3070; 9 | 10 | console.log('environment::::::', process.env.ENVIRONMENT); 11 | console.log('DB_CONNECTION_STR:::::::::::::', process.env.DB_CONNECTION_STR); 12 | console.log('DB USERNAME::::::', process.env.DB_USERNAME); 13 | console.log('DB PASSWORD::::::', process.env.DB_PASSWORD); 14 | 15 | app.use(bodyParser.json()); 16 | 17 | app.get('/', (req, res) => { 18 | logger.info('default route'); 19 | res.send(process.env.API_WORKS_MESSAGE); 20 | }); 21 | 22 | app.use('/api', require('./routes/routes')); 23 | 24 | // request to handle undefined or all other routes 25 | app.get('*', (req, res) => { 26 | logger.info('users route'); 27 | res.send(process.env.API_WORKS_MESSAGE); 28 | }); 29 | 30 | app.listen(port, (err) => { 31 | if (err) { 32 | logger.error('Error::', err); 33 | } 34 | logger.info(`running server on from port:::::::${port}`); 35 | }); 36 | -------------------------------------------------------------------------------- /jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | 4 | stages { 5 | stage('Build') { 6 | steps { 7 | echo 'Building..' 8 | } 9 | } 10 | stage('Test') { 11 | steps { 12 | echo 'Testing..' 13 | } 14 | } 15 | stage('Deploy') { 16 | steps { 17 | echo 'Deploying....' 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /logger/logger.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | /* eslint-disable func-names */ 3 | const environment = process.env.ENVIRONMENT || 'development'; 4 | 5 | const Logger = function () {}; 6 | 7 | Logger.prototype.info = function (logText) { 8 | if (environment !== 'production') { 9 | console.log(`${new Date()}info:::::${logText}`); 10 | } 11 | }; 12 | 13 | Logger.prototype.debug = function (logText) { 14 | if (environment !== 'production') { 15 | console.log(`${new Date()}debug:::::${logText}`); 16 | } 17 | }; 18 | 19 | Logger.prototype.error = function (logText) { 20 | if (environment !== 'production') { 21 | console.log(`${new Date()}error:::::${logText}`); 22 | } 23 | }; 24 | 25 | module.exports = new Logger(); 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "user_api", 3 | "version": "1.0.0", 4 | "description": "sample rest api", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "ENVIRONMENT=$ENVIRONMENT node index.js", 8 | "start:dev": "nodemon index.js", 9 | "eslint": "eslint ./", 10 | "eslint-fix": "eslint ./ --fix", 11 | "build": "webpack", 12 | "prod": "node dist/api.bundle.js", 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "Bhargav Bachina", 16 | "license": "ISC", 17 | "dependencies": { 18 | "body-parser": "^1.18.3", 19 | "dotenv": "^8.2.0", 20 | "express": "^4.16.4" 21 | }, 22 | "devDependencies": { 23 | "dotenv-webpack": "^1.8.0", 24 | "eslint": "^5.13.0", 25 | "eslint-config-airbnb-base": "^13.1.0", 26 | "eslint-plugin-import": "^2.16.0", 27 | "nodemon": "^1.18.10", 28 | "webpack": "^4.29.3", 29 | "webpack-cli": "^3.2.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /routes/routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | 4 | const apiRouter = express(); 5 | 6 | 7 | apiRouter.use('/user', require('./user')); 8 | 9 | module.exports = apiRouter; 10 | -------------------------------------------------------------------------------- /routes/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | 4 | const logger = require('../logger/logger'); 5 | 6 | 7 | const app = express(); 8 | 9 | // array to hold users 10 | const users = [{ firstName: 'fnam1', lastName: 'lnam1', userName: 'username1' }]; 11 | 12 | // request to get all the users 13 | app.get('/users', (req, res) => { 14 | logger.info('users route'); 15 | res.json(users); 16 | }); 17 | 18 | // request to get all the users by userName 19 | app.get('/users/:userName', (req, res) => { 20 | logger.info(`filter users by username:::::${req.params.userName}`); 21 | const user = users.filter(usr => req.params.userName === usr.userName); 22 | res.json(user); 23 | }); 24 | 25 | // request to post the user 26 | // req.body has object of type {firstName:"fnam1",lastName:"lnam1",userName:"username1"} 27 | app.post('/user', (req, res) => { 28 | users.push(req.body); 29 | res.json(users); 30 | }); 31 | 32 | module.exports = app; 33 | -------------------------------------------------------------------------------- /webpack-dotenvplugin.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Dotenv = require('dotenv-webpack'); 3 | 4 | module.exports = { 5 | entry: './index.js', 6 | output: { 7 | path: path.resolve(__dirname, 'dist'), 8 | filename: 'api.bundle.js', 9 | }, 10 | target: 'node', 11 | plugins: [ 12 | new Dotenv({ 13 | path: './environments/.env-dev', // Path to .env file (this is the default) 14 | safe: false // load .env.example (defaults to "false" which does not use dotenv-safe) 15 | }), 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /webpack-envplugin.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | const environment = process.env.ENVIRONMENT; 5 | 6 | console.log('environment:::::', environment); 7 | 8 | const ENVIRONMENT_VARIABLES = { 9 | ENVIRONMENT: 'development', 10 | PORT: '9000', 11 | GREETING_MESSAGE: 'API Running In Development Environment', 12 | API_WORKS_MESSAGE: 'Development API Works!!!', 13 | DB_USERNAME: 'dev username', 14 | DB_PASSWORD: 'dev password', 15 | DB_CONNECTION_STR: 'dev connection string', 16 | }; 17 | 18 | module.exports = { 19 | entry: './index.js', 20 | output: { 21 | path: path.resolve(__dirname, 'dist'), 22 | filename: 'api.bundle.js', 23 | }, 24 | target: 'node', 25 | plugins: [ 26 | new webpack.EnvironmentPlugin(ENVIRONMENT_VARIABLES), 27 | ], 28 | }; 29 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | const environment = process.env.ENVIRONMENT; 5 | 6 | console.log('environment:::::', environment); 7 | 8 | let ENVIRONMENT_VARIABLES = { 9 | ENVIRONMENT: JSON.stringify('development'), 10 | PORT: JSON.stringify('9090'), 11 | GREETING_MESSAGE: JSON.stringify('API Running In Development Environment'), 12 | API_WORKS_MESSAGE: JSON.stringify('Development API Works!!!'), 13 | DB_USERNAME: JSON.stringify('dev username'), 14 | DB_PASSWORD: JSON.stringify('dev password'), 15 | DB_CONNECTION_STR: JSON.stringify('dev connection string'), 16 | }; 17 | 18 | if (environment === 'test') { 19 | ENVIRONMENT_VARIABLES = { 20 | ENVIRONMENT: JSON.stringify('test'), 21 | PORT: JSON.stringify('8090'), 22 | GREETING_MESSAGE: JSON.stringify('API Running In test Environment'), 23 | API_WORKS_MESSAGE: JSON.stringify('test API Works!!!'), 24 | DB_USERNAME: JSON.stringify('username'), 25 | DB_PASSWORD: JSON.stringify('password'), 26 | DB_CONNECTION_STR: JSON.stringify('connection string'), 27 | }; 28 | } else if (environment === 'production') { 29 | ENVIRONMENT_VARIABLES = { 30 | ENVIRONMENT: JSON.stringify('production'), 31 | PORT: JSON.stringify('7090'), 32 | GREETING_MESSAGE: JSON.stringify('API Running In production Environment'), 33 | API_WORKS_MESSAGE: JSON.stringify('production API Works!!!'), 34 | DB_USERNAME: JSON.stringify('prod username'), 35 | DB_PASSWORD: JSON.stringify('prod password'), 36 | DB_CONNECTION_STR: JSON.stringify('prod connection string'), 37 | }; 38 | } 39 | 40 | module.exports = { 41 | entry: './index.js', 42 | output: { 43 | path: path.resolve(__dirname, 'dist'), 44 | filename: 'api.bundle.js', 45 | }, 46 | target: 'node', 47 | plugins: [ 48 | new webpack.DefinePlugin(ENVIRONMENT_VARIABLES), 49 | 50 | ], 51 | }; 52 | --------------------------------------------------------------------------------