├── .babelrc ├── .env ├── .github └── workflows │ └── main.yaml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── README.md ├── package.json └── src ├── app.js ├── config └── config.js ├── controllers └── values.js ├── index.js ├── public └── node.jpg ├── routes └── values.js ├── swagger └── swagger.js ├── test └── value.test.js └── utils └── utils.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | PORT= 3000 2 | MESSAGE= "Server running in the port" 3 | NODE_ENV= "development" -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-18.04 8 | 9 | steps: 10 | - uses: actions/checkout@master 11 | - uses: actions/setup-node@v1 12 | with: 13 | node-version: 12 14 | 15 | - run: npm install 16 | - run: npm run test 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | public -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "printWidth": 80, 6 | "tabWidth": 2, 7 | "useTabs": false 8 | } 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | sudo: false 4 | 5 | node_js: 6 | - "8.11.1" 7 | 8 | install: 9 | - npm install 10 | 11 | script: 12 | - npm run test 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmbl1685/express-restapi-es6/1a2a7234e1b7c1a514b64ebdf1a168ae8afdb578/README.md -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-restapi-es6", 3 | "version": "1.1.9", 4 | "description": "Custom structure to build an REST API using Express.js", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node ./node_modules/babel-cli/lib/babel-node src/index.js", 8 | "dev": "nodemon src/index.js --exec babel-node", 9 | "lint": "prettier --write src/**/*.*", 10 | "test": "mocha src/test/*.test.js --spec --timeout 5000 --exit --compilers js:babel-core/register", 11 | "test:nodemon": "nodemon src/test/value.test.js --exec mocha --compilers js:babel-core/register" 12 | }, 13 | "license": "MIT", 14 | "dependencies": { 15 | "babel-cli": "^6.26.0", 16 | "babel-preset-es2015": "^6.24.1", 17 | "chalk": "^2.4.2", 18 | "cors": "^2.8.5", 19 | "dotenv": "^8.1.0", 20 | "express": "^4.17.1", 21 | "helmet": "^3.21.1", 22 | "swagger-jsdoc": "^3.4.0", 23 | "swagger-ui-express": "^4.1.1" 24 | }, 25 | "devDependencies": { 26 | "chai": "^4.1.2", 27 | "chai-http": "^4.0.0", 28 | "mocha": "^5.2.0", 29 | "morgan": "^1.9.0", 30 | "nodemon": "^1.17.5", 31 | "prettier": "^1.18.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import express from 'express'; 4 | import helmet from 'helmet'; 5 | import cors from 'cors'; 6 | import swaggerUi from 'swagger-ui-express'; 7 | import { swaggerSpec } from './swagger/swagger'; 8 | import 'dotenv/config'; 9 | 10 | const app = express(); 11 | 12 | app.use(express.json()); 13 | app.use(express.urlencoded({ extended: false })); 14 | app.use(cors()); 15 | 16 | if (process.env.NODE_ENV === 'development') { 17 | app.use(require('morgan')('dev')); 18 | } 19 | 20 | app.use(helmet()); 21 | app.use(express.static(__dirname + '/src/public')); 22 | 23 | /* Swagger */ 24 | app.use('/api-docs', swaggerUi.serve); 25 | app.get('/api-docs', swaggerUi.setup(swaggerSpec)); 26 | app.get('/', (req, res, next) => res.redirect('api-docs')); 27 | 28 | /* Routes */ 29 | 30 | import valueRoutes from './routes/values'; 31 | 32 | app.use('/', valueRoutes); 33 | 34 | export default app; 35 | -------------------------------------------------------------------------------- /src/config/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | * Your config - DB Connections, Logs, Message, Key, etc... 5 | */ 6 | 7 | -------------------------------------------------------------------------------- /src/controllers/values.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * getValue controller 5 | * 6 | * @export 7 | * @param {any} request 8 | * @param {any} response 9 | * @param {any} next 10 | */ 11 | export const getValue = (req, res, next) => { 12 | try { 13 | res.status(200).send({ 14 | data: [], 15 | status: 'success', 16 | }); 17 | } catch (err) { 18 | res.status(404).send({ 19 | message: err.message, 20 | status: 'failure', 21 | }); 22 | } 23 | }; 24 | 25 | /** 26 | * getValueById controller 27 | * 28 | * @export 29 | * @param {any} request 30 | * @param {any} response 31 | * @param {any} next 32 | */ 33 | export const getValueById = (req, res, next) => { 34 | try { 35 | res.status(200).send({ 36 | data: [], 37 | status: 'success', 38 | }); 39 | } catch (err) { 40 | res.status(404).send({ 41 | message: err.message, 42 | status: 'failure', 43 | }); 44 | } 45 | }; 46 | 47 | /** 48 | * addValue controller 49 | * 50 | * @export 51 | * @param {any} request 52 | * @param {any} response 53 | * @param {any} next 54 | */ 55 | export const addValue = (req, res, next) => { 56 | try { 57 | res.status(200).send({ 58 | data: 'Value added', 59 | status: 'success', 60 | }); 61 | } catch (err) { 62 | res.status(404).send({ 63 | message: err.message, 64 | status: 'failure', 65 | }); 66 | } 67 | }; 68 | 69 | /** 70 | * updateValue controller 71 | * 72 | * @export 73 | * @param {any} request 74 | * @param {any} response 75 | * @param {any} next 76 | */ 77 | export const updateValue = (req, res, next) => { 78 | try { 79 | res.status(200).send({ 80 | data: 'Value updated', 81 | status: 'success', 82 | }); 83 | } catch (err) { 84 | res.status(404).send({ 85 | message: err.message, 86 | status: 'failure', 87 | }); 88 | } 89 | }; 90 | 91 | /** 92 | * deleteValue controller 93 | * 94 | * @export 95 | * @param {any} request 96 | * @param {any} response 97 | * @param {any} next 98 | */ 99 | export const deleteValue = (req, res, next) => { 100 | try { 101 | res.status(200).send({ 102 | data: 'Value deleted', 103 | status: 'success', 104 | }); 105 | } catch (err) { 106 | res.status(404).send({ 107 | message: err.message, 108 | status: 'failure', 109 | }); 110 | } 111 | }; 112 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import app from './app'; 4 | import chalk from 'chalk'; 5 | import 'dotenv/config'; 6 | 7 | app.set('port', process.env.PORT); 8 | app.set('message', process.env.MESSAGE); 9 | 10 | const port = app.get('port'); 11 | const message = app.get('message'); 12 | 13 | app.listen(port, () => { 14 | console.log(chalk.blue(`${message} ${port}`)); 15 | }); 16 | -------------------------------------------------------------------------------- /src/public/node.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmbl1685/express-restapi-es6/1a2a7234e1b7c1a514b64ebdf1a168ae8afdb578/src/public/node.jpg -------------------------------------------------------------------------------- /src/routes/values.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Values Routes 5 | * @module routes/values 6 | * @requires controllers/values 7 | */ 8 | 9 | import { Router } from 'express'; 10 | 11 | const router = Router(); 12 | 13 | import * as ctrlValue from '../controllers/values'; 14 | 15 | /** 16 | * @swagger 17 | * /api/value: 18 | * post: 19 | * tags: 20 | * - "Values" 21 | * description: "Add value" 22 | * operationId: ctrlValue.addValue 23 | * produces: 24 | * - application/json 25 | * responses: 26 | * '200': 27 | * description: Add Value Response 28 | * content: 29 | * application/json: 30 | * schema: 31 | * type: object 32 | * properties: 33 | * message: 34 | * type: string 35 | * status: 36 | * type: string 37 | * '400': 38 | * description: Bad Request 39 | * content: 40 | * application/json: 41 | * schema: 42 | * type: object 43 | * properties: 44 | * message: 45 | * type: string 46 | * description: Message = Invalid request 47 | * status: 48 | * type: string 49 | * description: Status = failure 50 | */ 51 | router.post('/api/value', ctrlValue.addValue); 52 | 53 | /** 54 | * @swagger 55 | * /api/value: 56 | * get: 57 | * tags: 58 | * - "Values" 59 | * description: "Get values" 60 | * operationId: ctrlValue.getValue 61 | * produces: 62 | * - application/json 63 | * responses: 64 | * '200': 65 | * description: Add Value Response 66 | * content: 67 | * application/json: 68 | * schema: 69 | * type: object 70 | * properties: 71 | * message: 72 | * type: string 73 | * status: 74 | * type: string 75 | * '400': 76 | * description: Bad Request 77 | * content: 78 | * application/json: 79 | * schema: 80 | * type: object 81 | * properties: 82 | * message: 83 | * type: string 84 | * description: Message = Invalid request 85 | * status: 86 | * type: string 87 | * description: Status = failure 88 | */ 89 | router.get('/api/value', ctrlValue.getValue); 90 | 91 | /** 92 | * @swagger 93 | * /api/value/{id}: 94 | * get: 95 | * tags: 96 | * - "Values" 97 | * description: "Get value by Id" 98 | * operationId: ctrlValue.getValueById 99 | * produces: 100 | * - application/json 101 | * parameters: 102 | * - name: id 103 | * in: path 104 | * description: Unique identifier of Values 105 | * required: true 106 | * schema: 107 | * type: string 108 | * responses: 109 | * '200': 110 | * description: Add Value Response 111 | * content: 112 | * application/json: 113 | * schema: 114 | * type: object 115 | * properties: 116 | * message: 117 | * type: string 118 | * status: 119 | * type: string 120 | * '400': 121 | * description: Bad Request 122 | * content: 123 | * application/json: 124 | * schema: 125 | * type: object 126 | * properties: 127 | * message: 128 | * type: string 129 | * description: Message = Invalid request 130 | * status: 131 | * type: string 132 | * description: Status = failure 133 | */ 134 | router.get('/api/value/:id', ctrlValue.getValueById); 135 | 136 | /** 137 | * @swagger 138 | * /api/value/{id}: 139 | * put: 140 | * tags: 141 | * - "Values" 142 | * description: "Update value" 143 | * operationId: ctrlValue.updateValue 144 | * produces: 145 | * - application/json 146 | * parameters: 147 | * - name: id 148 | * in: path 149 | * description: Unique identifier of Values 150 | * required: true 151 | * schema: 152 | * type: string 153 | * responses: 154 | * '200': 155 | * description: Update Value Response 156 | * content: 157 | * application/json: 158 | * schema: 159 | * type: object 160 | * properties: 161 | * message: 162 | * type: string 163 | * status: 164 | * type: string 165 | * '400': 166 | * description: Bad Request 167 | * content: 168 | * application/json: 169 | * schema: 170 | * type: object 171 | * properties: 172 | * message: 173 | * type: string 174 | * description: Message = Invalid request 175 | * status: 176 | * type: string 177 | * description: Status = failure 178 | */ 179 | router.put('/api/value/:id', ctrlValue.updateValue); 180 | 181 | /** 182 | * @swagger 183 | * /api/value/{id}: 184 | * delete: 185 | * tags: 186 | * - "Values" 187 | * description: "Delete value" 188 | * operationId: ctrlValue.deleteValue 189 | * produces: 190 | * - application/json 191 | * parameters: 192 | * - name: id 193 | * in: path 194 | * description: Unique identifier of Values 195 | * required: true 196 | * schema: 197 | * type: string 198 | * responses: 199 | * '200': 200 | * description: Delete Value Response 201 | * content: 202 | * application/json: 203 | * schema: 204 | * type: object 205 | * properties: 206 | * message: 207 | * type: string 208 | * status: 209 | * type: string 210 | * '400': 211 | * description: Bad Request 212 | * content: 213 | * application/json: 214 | * schema: 215 | * type: object 216 | * properties: 217 | * message: 218 | * type: string 219 | * description: Message = Invalid request 220 | * status: 221 | * type: string 222 | * description: Status = failure 223 | */ 224 | router.delete('/api/value/:id', ctrlValue.deleteValue); 225 | 226 | export default router; 227 | -------------------------------------------------------------------------------- /src/swagger/swagger.js: -------------------------------------------------------------------------------- 1 | import swaggerJsdoc from 'swagger-jsdoc'; 2 | const { version } = require('../../package.json'); 3 | 4 | /* 5 | Open API 6 | - https://swagger.io/docs/specification/about 7 | - https://swagger.io/specification 8 | */ 9 | 10 | const url = 'http://localhost:3000'; 11 | 12 | const swaggerDefinition = { 13 | info: { 14 | contact: { 15 | email: 'jmbl1685@hotmail.com', 16 | name: 'Juan Batty', 17 | }, 18 | description: 'Custom structure to build an REST API using Express.js', 19 | license: { 20 | name: 'All Rights Reserved', 21 | }, 22 | title: 'Custom structure to build an REST API using Express.js', 23 | version, 24 | }, 25 | openapi: '3.0.0', 26 | produces: ['application/json'], 27 | servers: [{ url }], 28 | tags: [ 29 | { 30 | description: 'Values', 31 | name: 'Values', 32 | }, 33 | ], 34 | 'x-tagGroups': [ 35 | { 36 | name: 'General', 37 | tags: ['Values'], 38 | }, 39 | ], 40 | components: { 41 | securitySchemes: { 42 | bearerAuth: { 43 | bearerFormat: 'JWT', 44 | scheme: 'bearer', 45 | type: 'http', 46 | }, 47 | }, 48 | }, 49 | }; 50 | 51 | const route = fileName => `./src/routes/${fileName}.js`; 52 | 53 | const apis = [route('values')]; 54 | 55 | const options = { 56 | apis, 57 | basePath: '/', 58 | swaggerDefinition, 59 | }; 60 | 61 | export const swaggerSpec = swaggerJsdoc(options); 62 | -------------------------------------------------------------------------------- /src/test/value.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import chai from 'chai'; 4 | import server from '../app'; 5 | import chaiHttp from 'chai-http'; 6 | const expect = chai.expect; 7 | 8 | chai.use(chaiHttp); 9 | 10 | describe('ValueController Test', () => { 11 | const body = { id: 'A12345', value: 'Juan Batty' }; 12 | 13 | it('POST api/value', done => { 14 | chai 15 | .request(server) 16 | .post('/api/value') 17 | .send(body) 18 | .end((err, res) => { 19 | if (err) done(err); 20 | expect(res).to.have.status(200); 21 | done(); 22 | }); 23 | }); 24 | 25 | it('GET api/value', done => { 26 | chai 27 | .request(server) 28 | .get('/api/value') 29 | .end((err, res) => { 30 | if (err) done(err); 31 | expect(res).to.have.status(200); 32 | expect(res.body).to.property('data'); 33 | done(); 34 | }); 35 | }); 36 | 37 | it('PUT api/value', done => { 38 | const id = '12345'; 39 | 40 | chai 41 | .request(server) 42 | .put(`/api/value/${id}`) 43 | .send(body) 44 | .end((err, res) => { 45 | if (err) done(err); 46 | expect(res).to.have.status(200); 47 | expect(res.body).to.property('data'); 48 | done(); 49 | }); 50 | }); 51 | 52 | it('DELETE api/value', done => { 53 | const id = '12345'; 54 | 55 | chai 56 | .request(server) 57 | .delete(`/api/value/${id}`) 58 | .end((err, res) => { 59 | if (err) done(err); 60 | expect(res).to.have.status(200); 61 | expect(res.body).to.property('data'); 62 | done(); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Get random Id - generateID 5 | * 6 | * @return {number} a random integer id. 7 | */ 8 | export const generateID = () => 9 | `_${Math.random() 10 | .toString(36) 11 | .substr(2, 9)}`; 12 | --------------------------------------------------------------------------------