├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── README.md ├── config ├── env │ ├── common.js │ ├── development.js │ └── production.js └── index.js ├── controllers ├── authenticationController.js └── userController.js ├── models └── Users │ ├── UserModel.js │ └── UserModelHandler.js ├── package.json ├── routes ├── authenticationRoutes.js ├── index.js └── userRoutes.js ├── server.js └── utilities ├── authentication ├── index.js └── localStrategy.js ├── constants └── index.js ├── handlers ├── errorHandler.js ├── hashHandler.js └── responseHandler.js └── validators ├── index.js ├── validationChecker.js └── validationError.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "@babel/plugin-proposal-class-properties", 7 | ["module-resolver", { 8 | "root": ["."], 9 | "alias": { 10 | "test": "./test" 11 | } 12 | }], 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | coverage 4 | dist 5 | node_modules 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "modules": true 4 | }, 5 | "env": { 6 | "es6": true 7 | }, 8 | "extends": "eslint-config-airbnb-base", 9 | "settings": { 10 | "import/resolver": { 11 | "node": { 12 | "moduleDirectory": [ 13 | "node_modules", 14 | "/" 15 | ] 16 | } 17 | } 18 | }, 19 | "rules": { 20 | "id-length": [ 21 | 2, 22 | { 23 | "min": 3, 24 | "max": 35, 25 | "properties": "never", 26 | "exceptions": [ "_", "cb", "db","fs", "$" ] 27 | } 28 | ], 29 | "max-len": [ 2, 120, 2 ], 30 | "max-params": [ 2, 3 ], 31 | "no-cond-assign": [ 2, "except-parens" ], 32 | "quote-props": 0, 33 | "import/no-extraneous-dependencies": [ 34 | "warn", 35 | { "devDependencies": true } 36 | ], 37 | "unicode-bom": 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | coverage 4 | dist 5 | node_modules 6 | npm-debug.log 7 | yarn.lock 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Express RESTful Starter 2 | 3 | This is a starter kit for building RESTful APIs with ES6, Express framework and Passport 4 | 5 | ## Getting started 6 | 7 | --------------- 8 | 9 | ```sh 10 | # Clone the repository 11 | git clone git@github.com:nutboltu/express-restful-starter.git 12 | cd express-restful-starter 13 | 14 | # Remove this git config 15 | rm -rf .git 16 | 17 | # Install dependencies 18 | npm i 19 | 20 | # Start server in development environment 21 | npm start 22 | 23 | # Start server in production environment 24 | npm start:prod 25 | ``` 26 | 27 | The api service runs on port 3000. We implemented following apis in this starter kit 28 | 29 | ``` 30 | BASE_PATH: http://localhost:3000/api/ 31 | 32 | Authentication 33 | POST /login 34 | Request: 35 | body:{ 36 | username: // for mock-data farhad.yasir 37 | password: // for mock-data 123456 38 | } 39 | Response: 40 | { 41 | user: // a demo user info 42 | } 43 | Users **You must be loggedIn before calling these apis** 44 | POST /users 45 | Request: 46 | body:{ 47 | firstName: user's first name, 48 | lastName: user's last name, 49 | email: user's email, 50 | password: user's password, 51 | } 52 | Response: 53 | { 54 | // returns same body for now. You need to update code in 55 | // /models/handlers/user.model.handlers.js 56 | firstName: user's first name, 57 | lastName: user's last name, 58 | email: user's email, 59 | password: user's password, 60 | } 61 | PUT /users/:id 62 | Response: 63 | { 64 | // returns same body for now. You need to update code in 65 | // /models/handlers/user.model.handlers.js 66 | firstName: user's first name, 67 | lastName: user's last name, 68 | email: user's email, 69 | password: user's password, 70 | } 71 | GET /users/:offset/:limit 72 | Response: 73 | { 74 | // returns offset and limit for now. You need to update code in 75 | // /models/handlers/user.model.handlers.js 76 | offset: url's offset, 77 | limit: url's limit, 78 | } 79 | GET /users/:id 80 | Response: 81 | { 82 | // returns id for now. You need to update code in 83 | // /models/handlers/user.model.handlers.js 84 | id 85 | } 86 | DELETE /users/:id 87 | Response: 88 | { 89 | // returns id for now. You need to update code in 90 | // /models/handlers/user.model.handlers.js 91 | id 92 | } 93 | ``` 94 | 95 | ## Starter Kit Layout 96 | 97 | --------------- 98 | 99 | ``` 100 | +- config 101 | | +- env --> environment dependable configuration files 102 | | +- common.js --> common configurations for all environment 103 | | +- development.js --> configurations for development 104 | | +- production.js --> configurations for production 105 | | +- index.js --> configuration file where all configurations are concatenated 106 | +- controllers --> controller files 107 | +- routes --> REST api routers 108 | +- models --> models directories that communicate with the database 109 | | +- {Entity Name} --> database access layer that connects with the db models 110 | +- node_modules --> development dependencies node modules 111 | +- utilities --> utilities files 112 | | +- authentication --> uses passport as authentication 113 | | +- constants --> consists application constants 114 | | +- handlers --> any kinds of handlers (e.g: errorHandler, responseHandler) 115 | | +- validators --> customize express validators 116 | +- server.js --> application run file 117 | +- package.json --> node package 118 | ``` 119 | 120 | ## Licence 121 | 122 | MIT licence 123 | -------------------------------------------------------------------------------- /config/env/common.js: -------------------------------------------------------------------------------- 1 | export default { 2 | sessionSecret: 'yourSecretKey', 3 | sessionMaxAge: 3600000, 4 | }; 5 | -------------------------------------------------------------------------------- /config/env/development.js: -------------------------------------------------------------------------------- 1 | export default { 2 | host: 'localhost', 3 | port: 3000, 4 | version: '1.0', 5 | } 6 | -------------------------------------------------------------------------------- /config/env/production.js: -------------------------------------------------------------------------------- 1 | export default { 2 | host: 'your production host', 3 | port: 3000, 4 | version: '1.0', 5 | }; 6 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | import common from './env/common'; 2 | import development from './env/development'; 3 | import production from './env/production'; 4 | 5 | const envConfig = process.env.NODE_ENV === 'production' ? 6 | production : development; 7 | 8 | export default Object.assign(common, envConfig); 9 | -------------------------------------------------------------------------------- /controllers/authenticationController.js: -------------------------------------------------------------------------------- 1 | import responseHandler from 'utilities/handlers/responseHandler'; 2 | import Authenticator from 'utilities/authentication'; 3 | 4 | const login = (req, res, next) => { 5 | const authenticator = new Authenticator(); 6 | authenticator.authenticate('local', function(err, user) { 7 | if (err) { 8 | responseHandler.res(err, null, res); 9 | } 10 | req.logIn(user, function(err) { 11 | if (err) { 12 | responseHandler.res(err, null, res); 13 | } 14 | return responseHandler.res(err, user, res); 15 | }); 16 | })(req, res, next); 17 | }; 18 | 19 | export default { 20 | login, 21 | }; 22 | -------------------------------------------------------------------------------- /controllers/userController.js: -------------------------------------------------------------------------------- 1 | import responseHandler from 'utilities/handlers/responseHandler'; 2 | import userModelHandler from 'models/Users/userModelHandler'; 3 | 4 | const add = (req, res) => { 5 | userModelHandler.add(req.body, (err, user) => { 6 | responseHandler.res(err, user, res); 7 | }); 8 | }; 9 | 10 | const findAll = (req, res) => { 11 | const offset = req.params.offset || 0; 12 | const limit = req.params.limit || 10; 13 | userModelHandler.findAll(offset, limit, (err, users) => { 14 | responseHandler.res(err, users, res); 15 | }); 16 | }; 17 | 18 | const findById = (req, res) => { 19 | userModelHandler.findById(req.params.id, (err, user) => { 20 | responseHandler.res(err, user, res); 21 | }); 22 | }; 23 | 24 | const remove = (req, res) => { 25 | userModelHandler.remove(req.params.id, (err, removed) => { 26 | responseHandler.res(err, removed, res); 27 | }); 28 | }; 29 | 30 | const update = (req, res) => { 31 | userModelHandler.update(req.params.id, req.body, (err, user) => { 32 | responseHandler.res(err, user, res); 33 | }); 34 | }; 35 | 36 | export default { 37 | add, 38 | findAll, 39 | findById, 40 | remove, 41 | update, 42 | }; 43 | -------------------------------------------------------------------------------- /models/Users/UserModel.js: -------------------------------------------------------------------------------- 1 | export default class UserModel { 2 | constructor(userData) { 3 | this.user = { 4 | id: userData.id, 5 | username: userData.username, 6 | email: userData.email, 7 | password: userData.password, 8 | firstName: userData.firstName, 9 | lastName: userData.lastName, 10 | } 11 | return this; 12 | } 13 | 14 | getId() { 15 | return this.user.id; 16 | } 17 | 18 | getUsername() { 19 | return this.user.username; 20 | } 21 | 22 | validPassword(password) { 23 | return this.user.password === password; 24 | } 25 | 26 | toObject() { 27 | return this.user; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /models/Users/UserModelHandler.js: -------------------------------------------------------------------------------- 1 | import User from './UserModel'; 2 | /** 3 | * Mock Records - We created a mock records for testing login authentications 4 | */ 5 | const records = [ 6 | new User({ 7 | id: '1', 8 | username: 'farhad.yasir', 9 | email: 'farhad.yasir@demo.com', 10 | password: '123456', 11 | firstName: 'Farhad', 12 | lastName: 'Yasir', 13 | }), 14 | new User({ 15 | id: '2', 16 | username: 'john.smith', 17 | email: 'john.smith@demo.com', 18 | password: '123456', 19 | firstName: 'John', 20 | lastName: 'Smith', 21 | }) 22 | ] 23 | 24 | const add = (newUser, cb) => { 25 | records.push(new User(newUser)); 26 | cb(null, records[records.length - 1]); 27 | }; 28 | 29 | const findAll = (offset, limit, cb) => { 30 | cb(null, records); 31 | }; 32 | 33 | const findById = (id, cb) => { 34 | const user = records.find(user => user.getId() === id); 35 | cb(null, user); 36 | }; 37 | 38 | const findByUsername = (username, cb) => { 39 | const user = records.find(user => user.getUsername() === username); 40 | cb(null, user); 41 | }; 42 | 43 | const remove = (id, cb) => { 44 | // your code here 45 | cb(null, id); 46 | }; 47 | 48 | const update = (id, user, cb) => { 49 | // your code here 50 | cb(null, user); 51 | }; 52 | 53 | export default { 54 | add, 55 | findAll, 56 | findById, 57 | findByUsername, 58 | remove, 59 | update, 60 | } 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-restful-starter", 3 | "version": "1.0.0", 4 | "private": false, 5 | "main": "server.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git@github.com:nutboltu/express-restful-starter.git" 9 | }, 10 | "scripts": { 11 | "start": "NODE_ENV=development nodemon --exec $(npm bin)/babel-node server.js", 12 | "start:prod": "NODE_ENV=production $(npm bin)/babel-node server.js" 13 | }, 14 | "keywords": [ 15 | "node express starter", 16 | "express rest api starter", 17 | "express es6" 18 | ], 19 | "author": "Farhad Yasir", 20 | "license": "MIT", 21 | "dependencies": { 22 | "bcrypt": "^1.0.3", 23 | "body-parser": "^1.18.2", 24 | "cookie-parser": "^1.4.3", 25 | "express": "^4.16.2", 26 | "express-session": "^1.15.6", 27 | "express-validator": "^4.3.0", 28 | "passport": "^0.4.0", 29 | "passport-local": "^1.0.0", 30 | "winston": "^2.4.0" 31 | }, 32 | "devDependencies": { 33 | "@babel/cli": "^7.2.3", 34 | "@babel/core": "^7.4.0", 35 | "@babel/node": "^7.2.2", 36 | "@babel/plugin-proposal-class-properties": "^7.4.0", 37 | "@babel/preset-env": "^7.4.2", 38 | "babel-plugin-module-resolver": "^3.2.0", 39 | "eslint": "^4.11.0", 40 | "eslint-config-airbnb-base": "^12.1.0", 41 | "nodemon": "^1.12.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /routes/authenticationRoutes.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | import authenticationController from 'controllers/authenticationController'; 4 | import validationChecker from 'utilities/validators/validationChecker'; 5 | import validationError from 'utilities/validators/validationError'; 6 | 7 | const router = express.Router(); 8 | 9 | router.post('/login', authenticationController.login); 10 | export default router; 11 | 12 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import authenticationRouter from './authenticationRoutes'; 3 | import userRouter from './userRoutes'; 4 | 5 | const router = express.Router(); 6 | 7 | const allowCrossDomain = (req, res, next) => { 8 | res.header('Access-Control-Allow-Credentials', true); 9 | res.header('Access-Control-Allow-Origin', '*'); 10 | res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, PATCH, DELETE, OPTIONS'); 11 | res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); 12 | next(); 13 | }; 14 | 15 | router.use('/', authenticationRouter); 16 | router.use('/users', userRouter); 17 | 18 | export default { 19 | allowCrossDomain, 20 | router, 21 | } 22 | 23 | -------------------------------------------------------------------------------- /routes/userRoutes.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | import userController from 'controllers/userController'; 4 | import validationChecker from 'utilities/validators/validationChecker'; 5 | import validationError from 'utilities/validators/validationError'; 6 | import { isAuthenticated } from 'utilities/authentication'; 7 | 8 | const validateUserParameter = (req, res, next) => { 9 | validationChecker.areRequired(req, ['firstName', 'lastName', 'email', 'password']); 10 | validationError.processErrors(req, res, next); 11 | }; 12 | 13 | const router = express.Router(); 14 | 15 | router.post('/', [ validateUserParameter, userController.add]) 16 | .put('/:id', [ validateUserParameter, userController.update]) 17 | .get('/:offset/:limit', [ userController.findAll]) 18 | .get('/:id', [isAuthenticated, userController.findById]) 19 | .delete('/:id', [ userController.remove]); 20 | 21 | export default router; 22 | 23 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import bodyParser from 'body-parser'; 2 | import cookieParser from 'cookie-parser'; 3 | import express from 'express'; 4 | import expressSession from 'express-session'; 5 | import * as logger from 'winston'; 6 | 7 | import config from 'config'; 8 | import expressValidator from 'utilities/validators'; 9 | import Authenticator from 'utilities/authentication'; 10 | import route from 'routes'; 11 | 12 | const app = express(); 13 | const authenticator = new Authenticator(); 14 | 15 | app.use(cookieParser(config.sessionSecret)); 16 | app.use(bodyParser.json()); 17 | app.use(bodyParser.urlencoded({ extended: false })); 18 | app.use(expressSession({ 19 | secret: config.sessionSecret, 20 | resave: false, 21 | saveUninitialized: true, 22 | cookie: { 23 | maxAge: config.sessionMaxAge, 24 | }, 25 | })); 26 | app.use(authenticator.initialize()); 27 | app.use(authenticator.session()); 28 | app.use(expressValidator); 29 | app.use(route.allowCrossDomain); 30 | app.use('/api', route.router); 31 | 32 | app.listen(config.port, () => { 33 | logger.info('Listening on port %d', config.port); 34 | }); 35 | 36 | 37 | export default app; 38 | -------------------------------------------------------------------------------- /utilities/authentication/index.js: -------------------------------------------------------------------------------- 1 | import passport from 'passport'; 2 | import responseHandler from 'utilities/handlers/responseHandler'; 3 | import errorHandler from 'utilities/handlers/errorHandler'; 4 | import UserModelHandler from 'models/Users/UserModelHandler'; 5 | import localStrategy from './localStrategy'; 6 | 7 | export default class Authentication { 8 | constructor() { 9 | if (!global.authenticator) { 10 | global.authenticator = passport; 11 | global.authenticator.use(localStrategy); 12 | 13 | global.authenticator.serializeUser(function(user, cb) { 14 | cb(null, user.id); 15 | }); 16 | 17 | global.authenticator.deserializeUser(function(id, cb) { 18 | UserModelHandler.findById(id, function (err, user) { 19 | if (err) { return cb(err); } 20 | cb(null, user.toObject()); 21 | }); 22 | }); 23 | } 24 | return global.authenticator; 25 | } 26 | }; 27 | 28 | export function isAuthenticated(req, res, next) { 29 | if(req.isAuthenticated()) return next(); 30 | return responseHandler.res(errorHandler.PERMISSION_DENIED, null, res); 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /utilities/authentication/localStrategy.js: -------------------------------------------------------------------------------- 1 | 2 | import { Strategy } from 'passport-local'; 3 | import UserModelHandler from 'models/Users/UserModelHandler'; 4 | import errorHandler from 'utilities/handlers/errorHandler'; 5 | 6 | const localStrategy = new Strategy( 7 | function(username, password, done) { 8 | UserModelHandler.findByUsername(username, function (err, user) { 9 | if (err) { 10 | return done(err); 11 | } 12 | if (!user) { 13 | return done(errorHandler.INVALID_USERNAME, null); 14 | } 15 | if (!user.validPassword(password)) { 16 | return done(errorHandler.INVALID_PASSWORD, null); 17 | } 18 | return done(null, user.toObject()); 19 | }); 20 | } 21 | ); 22 | 23 | export default localStrategy; 24 | -------------------------------------------------------------------------------- /utilities/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ERROR_STATUS = { 2 | ACCESS_TOKEN_EXPIRED: 'ACCESS_TOKEN_EXPIRED', 3 | DATA_NOT_FOUND: 'DATA_NOT_FOUND', 4 | EMAIL_EXISTS: 'EMAIL_EXISTS', 5 | INVALID_ACCESS_TOKEN: 'INVALID_ACCESS_TOKEN', 6 | INTERNAL_DB_ERROR: 'INTERNAL_DB_ERROR', 7 | INVALID_EMAIL: 'INVALID_EMAIL', 8 | INVALID_PARAMETER: 'INVALID_PARAMETER', 9 | INVALID_PASSWORD: 'INVALID_PASSWORD', 10 | INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR', 11 | PERMISSION_DENIED: 'PERMISSION_DENIED' 12 | }; 13 | 14 | export const STATUS = { 15 | ACTIVE: 'active', 16 | INACTIVE: 'inactive', 17 | PENDING: 'pending', 18 | DELETED: 'deleted' 19 | }; 20 | -------------------------------------------------------------------------------- /utilities/handlers/errorHandler.js: -------------------------------------------------------------------------------- 1 | const ERROR_CODE = { 2 | BAD_REQUEST: 400, 3 | UNAUTHORIZED: 401, 4 | NOT_FOUND: 404, 5 | INTERNAL_SERVER_ERROR: 500, 6 | 7 | }; 8 | 9 | const ACCESS_TOKEN_EXPIRED = new Error('Access token has expired'); 10 | ACCESS_TOKEN_EXPIRED.code = ERROR_CODE.BAD_REQUEST; 11 | 12 | const DATA_NOT_FOUND = new Error('Data not found'); 13 | DATA_NOT_FOUND.code = ERROR_CODE.NOT_FOUND; 14 | 15 | const EMAIL_EXISTS = new Error('Email address already exists'); 16 | EMAIL_EXISTS.code = ERROR_CODE.BAD_REQUEST; 17 | 18 | const INVALID_ACCESS_TOKEN = new Error('Invalid access token'); 19 | INVALID_ACCESS_TOKEN.code = ERROR_CODE.BAD_REQUEST; 20 | 21 | const INTERNAL_DB_ERROR = new Error('Internal database error'); 22 | INTERNAL_DB_ERROR.code = ERROR_CODE.INTERNAL_SERVER_ERROR; 23 | 24 | const INVALID_EMAIL = new Error('Invalid email address'); 25 | INVALID_EMAIL.code = ERROR_CODE.BAD_REQUEST; 26 | 27 | const INVALID_PARAMETER = new Error('Invalid parameter'); 28 | INVALID_PARAMETER.code = ERROR_CODE.BAD_REQUEST; 29 | 30 | const INVALID_PASSWORD = new Error('Invalid password'); 31 | INVALID_PASSWORD.code = ERROR_CODE.BAD_REQUEST; 32 | 33 | const INVALID_USERNAME = new Error('Invalid username'); 34 | INVALID_USERNAME.code = ERROR_CODE.BAD_REQUEST; 35 | 36 | const INTERNAL_SERVER_ERROR = new Error('Internal server error'); 37 | INTERNAL_SERVER_ERROR.code = ERROR_CODE.INTERNAL_SERVER_ERROR; 38 | 39 | const PERMISSION_DENIED = new Error('Permission denied'); 40 | PERMISSION_DENIED.code = ERROR_CODE.UNAUTHORIZED; 41 | 42 | export default { 43 | ACCESS_TOKEN_EXPIRED, 44 | DATA_NOT_FOUND, 45 | EMAIL_EXISTS, 46 | INVALID_ACCESS_TOKEN, 47 | INTERNAL_DB_ERROR, 48 | INVALID_EMAIL, 49 | INVALID_PARAMETER, 50 | INVALID_PASSWORD, 51 | INVALID_USERNAME, 52 | INTERNAL_SERVER_ERROR, 53 | PERMISSION_DENIED, 54 | } 55 | -------------------------------------------------------------------------------- /utilities/handlers/hashHandler.js: -------------------------------------------------------------------------------- 1 | import { compare, hash } from 'bcrypt'; 2 | 3 | const saltRounds = 8; // rounds=8 : ~40 hashes/sec 4 | 5 | const compareIt = (password, hashedPassword, callback) => { 6 | return compare(password, hashedPassword, callback); 7 | }; 8 | 9 | const hashIt = (text, callback) => { 10 | return hash(text, saltRounds, callback); 11 | }; 12 | 13 | export default { 14 | compareIt, 15 | hashIt 16 | }; 17 | -------------------------------------------------------------------------------- /utilities/handlers/responseHandler.js: -------------------------------------------------------------------------------- 1 | const res = (err, data, res) => { 2 | if (err) { 3 | // status code - Internal Server Error 4 | return res.status(err.code).json(err.message); 5 | } 6 | return res.status(200).json(data); 7 | }; 8 | 9 | export default { 10 | res, 11 | }; 12 | -------------------------------------------------------------------------------- /utilities/validators/index.js: -------------------------------------------------------------------------------- 1 | import expressValidator from 'express-validator'; 2 | 3 | export default expressValidator(); 4 | -------------------------------------------------------------------------------- /utilities/validators/validationChecker.js: -------------------------------------------------------------------------------- 1 | import config from 'config'; 2 | import { ERROR_STATUS } from 'utilities/constants'; 3 | 4 | const areRequired = (req, params) => { 5 | params.forEach((param) => { 6 | req.assert(param, `${param} is required`).notEmpty(); 7 | }); 8 | }; 9 | 10 | const isValidEmail = (req) => { 11 | req.assert('email', ERROR_STATUS.INVALID_EMAIL).isEmail(); 12 | }; 13 | 14 | const isValidPassword = (req) => { 15 | req.assert('password', ERROR_STATUS.INVALID_PASSWORD).matches(config.validPasswordRegEx); 16 | }; 17 | 18 | const isBoolean = (req, param) => { 19 | if (typeof req.param(param) === 'undefined' || req.param(param) === null) { 20 | req.assert(param, ERROR_STATUS.INVALID_PARAMETER).isBoolean(); 21 | } 22 | }; 23 | 24 | const hasValidToken = (req) => { 25 | req.checkHeaders('authorization', ERROR_STATUS.INVALID_ACCESS_TOKEN).notEmpty(); 26 | req.checkHeaders('authorization', ERROR_STATUS.INVALID_ACCESS_TOKEN).hasValidToken(); 27 | }; 28 | 29 | 30 | export default { 31 | areRequired, 32 | isValidEmail, 33 | isValidPassword, 34 | isBoolean, 35 | hasValidToken 36 | }; 37 | -------------------------------------------------------------------------------- /utilities/validators/validationError.js: -------------------------------------------------------------------------------- 1 | import * as logger from 'winston'; 2 | import errorHandler from 'utilities/handlers/errorHandler'; 3 | 4 | const processErrors = (req, res, next) => { 5 | const validationErrors = req.validationErrors(); 6 | if (validationErrors) { 7 | logger.error(validationErrors); 8 | const error = errorHandler[validationErrors[0].msg] || errorHandler.INVALID_PARAMETER; 9 | res.status(error.code).json(error.message); 10 | } 11 | else next(); 12 | }; 13 | 14 | export default { 15 | processErrors, 16 | } 17 | --------------------------------------------------------------------------------