├── .gitignore ├── LICENSE ├── README.md ├── config.js ├── controllers └── helloWorld.js ├── db └── db.js ├── flightplan.js ├── models └── helloWorld.js ├── package-lock.json ├── package.json ├── routes └── helloWorld.js └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 maciej jordanek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-simple 2 | > A project for fast development of REST APIs, where routes can return JSON documents 3 | 4 | Simple starter, barebone structure based on ExpressJS. Helps to easily create controllers for routes. Provides Flightplan file for simple deployment strategy. 5 | 6 | This project uses the following libraries: 7 | - [Express](https://www.npmjs.com/package/express) 8 | - [Helmet](https://www.npmjs.com/package/helmet) 9 | - [Morgan](https://www.npmjs.com/package/morgan) 10 | - [Body-parser](https://www.npmjs.com/package/body-parser) 11 | - [Flightplan](https://www.npmjs.com/package/flightplan) 12 | - [Fly](https://www.npmjs.com/package/fly) 13 | 14 | ## Installation 15 | Open your terminal and run the following commands: 16 | ``` 17 | git clone https://github.com/mjrdnk/express-simple 18 | cd express-simple/ && npm install 19 | ``` 20 | ## Usage 21 | To run express-simple in development, run this command from your project directory: 22 | 23 | ``` 24 | npm run dev 25 | ``` 26 | 27 | To run express-simple in production, run this command from your project directory: 28 | 29 | ``` 30 | npm start 31 | ``` 32 | 33 | Then, go to http://localhost:5000/api/v1.0/hello 34 | 35 | You will see this screen in your browser 36 | 37 |
38 | 39 | ## Examples 40 | 41 | #### Example : nexmo sms service 42 | To write your custom controllers write your functions in a file and export the module, like this: 43 | ```javascript 44 | const Nexmo = require('nexmo'); 45 | 46 | function nexmo () { 47 | this.nexmo = {} 48 | this.apiKey = yourapiKey; // get your api key and secret from nexmo.com 49 | this.apiSecret = yourapiSecret; 50 | this.sendSms = sendSms; 51 | } 52 | 53 | this.nex = new Nexmo ({ 54 | apiKey : this.apiKey, 55 | apiSecret : this.apiSecret 56 | }); 57 | 58 | let sendSms = (from,to,message) => { 59 | this.nex.message.sendSms(from, to, message, (err,responseData) => { 60 | if (err) { 61 | console.log('err', err.message); 62 | return; 63 | } 64 | }); 65 | } 66 | module.exports = nexmo; 67 | ``` 68 | 69 | The controller can be reused in a router nexmo.route.js file, like this: 70 | ```javascript 71 | const router = require(express).Router(); 72 | 73 | const NexmoController = require('../controllers/nexmo.js'); 74 | 75 | router.get('/sms', NexmoController.sendSms); 76 | 77 | module.export = router 78 | ``` 79 | 80 | Then you can use it in your server.js file, like this: 81 | ```javascript 82 | const nexmo = require('./routes/nexmo.route.js'); 83 | 84 | app.use(API_BASE, nexmo); 85 | ``` 86 | 87 | ## Enviroment Variables 88 | 89 | #### `$SSH_AUTH_SOCK` 90 | Contains the path of the unix file socket that the agent uses for communication with other processes. This is essential for `ssh-add`. [See more details](http://blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add/). 91 | 92 | 93 | ## Credit 94 | Flightplan based on [this gist](https://gist.github.com/learncodeacademy/35045e64d2bbe6eb14f9) 95 | 96 | ## License 97 | 98 | [MIT](LICENSE) 99 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | // place for your constants 2 | // !!! note for production: sensitive data should be included in environmental variables 3 | 4 | module.exports = { 5 | API_BASE: '/api/v1.0' 6 | }; -------------------------------------------------------------------------------- /controllers/helloWorld.js: -------------------------------------------------------------------------------- 1 | // place for your controller's functions 2 | 3 | // HelloWorldController defines methods 4 | // you can import them in your the corresponding route file in routes/ folder 5 | let HelloWorldController = { 6 | get: get 7 | }; 8 | 9 | function get (req, res, next) { 10 | res.json({ 11 | 'hello world': 'hello world' 12 | }); 13 | } 14 | 15 | module.exports = HelloWorldController; -------------------------------------------------------------------------------- /db/db.js: -------------------------------------------------------------------------------- 1 | // place for your database configuration -------------------------------------------------------------------------------- /flightplan.js: -------------------------------------------------------------------------------- 1 | // run on your deployment machine by typing executing: 2 | // fly development or fly production 3 | 4 | var plan = require('flightplan'); 5 | 6 | var appName = 'API_NAME'; 7 | var username = 'USERNAME'; // username on server machine 8 | var startFile = 'server.js'; 9 | 10 | var tmpDir = appName+'-' + new Date().getTime(); 11 | 12 | // configuration 13 | plan.target('development', [ 14 | { 15 | host: 'HOST_IP', 16 | username: username, 17 | agent: process.env.SSH_AUTH_SOCK 18 | } 19 | ]); 20 | 21 | plan.target('production', [ 22 | { 23 | host: 'HOST_IP', 24 | username: username, 25 | agent: process.env.SSH_AUTH_SOCK 26 | }, 27 | //add in another server if you have more than one 28 | // { 29 | // host: '104.131.93.216', 30 | // username: username, 31 | // agent: process.env.SSH_AUTH_SOCK 32 | // } 33 | ]); 34 | 35 | // run commands on localhost 36 | plan.local(function(local) { 37 | // uncomment these if you need to run a build on your machine first 38 | // local.log('Run build'); 39 | // local.exec('gulp build'); 40 | 41 | local.log('Copy files to remote hosts'); 42 | var filesToCopy = local.exec('git ls-files', {silent: true}); 43 | // rsync files to all the destination's hosts 44 | local.transfer(filesToCopy, '/tmp/' + tmpDir); 45 | }); 46 | 47 | // run commands on remote hosts (destinations) 48 | plan.remote(function(remote) { 49 | remote.log('Move folder to root'); 50 | remote.sudo('cp -R /tmp/' + tmpDir + ' ~', {user: username}); 51 | remote.rm('-rf /tmp/' + tmpDir); 52 | 53 | remote.log('Install dependencies'); 54 | remote.sudo('npm --production --prefix ~/' + tmpDir + ' install ~/' + tmpDir, {user: username}); 55 | 56 | remote.log('Reload application'); 57 | remote.sudo('ln -snf ~/' + tmpDir + ' ~/'+appName, {user: username}); 58 | 59 | remote.exec('cd ~/'+ appName + '&&' + 'forever start ./' + startFile, {failsafe: true}); 60 | remote.exec('cd ~/'+ appName + '&&' + 'forever start ./' + startFile); 61 | }); 62 | -------------------------------------------------------------------------------- /models/helloWorld.js: -------------------------------------------------------------------------------- 1 | // place for your ODM models -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weendify-api", 3 | "version": "0.0.5", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "base64url": { 8 | "version": "2.0.0", 9 | "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", 10 | "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=" 11 | }, 12 | "buffer-equal-constant-time": { 13 | "version": "1.0.1", 14 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 15 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 16 | }, 17 | "ecdsa-sig-formatter": { 18 | "version": "1.0.9", 19 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", 20 | "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", 21 | "requires": { 22 | "base64url": "2.0.0", 23 | "safe-buffer": "5.1.1" 24 | } 25 | }, 26 | "hoek": { 27 | "version": "2.16.3", 28 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", 29 | "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" 30 | }, 31 | "isemail": { 32 | "version": "1.2.0", 33 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", 34 | "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" 35 | }, 36 | "joi": { 37 | "version": "6.10.1", 38 | "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", 39 | "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", 40 | "requires": { 41 | "hoek": "2.16.3", 42 | "isemail": "1.2.0", 43 | "moment": "2.19.1", 44 | "topo": "1.1.0" 45 | } 46 | }, 47 | "jsonwebtoken": { 48 | "version": "7.4.3", 49 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz", 50 | "integrity": "sha1-d/UCHeBYtgWheD+hKD6ZgS5kVjg=", 51 | "requires": { 52 | "joi": "6.10.1", 53 | "jws": "3.1.4", 54 | "lodash.once": "4.1.1", 55 | "ms": "2.0.0", 56 | "xtend": "4.0.1" 57 | } 58 | }, 59 | "jwa": { 60 | "version": "1.1.5", 61 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", 62 | "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", 63 | "requires": { 64 | "base64url": "2.0.0", 65 | "buffer-equal-constant-time": "1.0.1", 66 | "ecdsa-sig-formatter": "1.0.9", 67 | "safe-buffer": "5.1.1" 68 | } 69 | }, 70 | "jws": { 71 | "version": "3.1.4", 72 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", 73 | "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", 74 | "requires": { 75 | "base64url": "2.0.0", 76 | "jwa": "1.1.5", 77 | "safe-buffer": "5.1.1" 78 | } 79 | }, 80 | "lodash.once": { 81 | "version": "4.1.1", 82 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 83 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 84 | }, 85 | "moment": { 86 | "version": "2.19.1", 87 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.1.tgz", 88 | "integrity": "sha1-VtoaLRy/AdOLfhr8McELz6GSkWc=" 89 | }, 90 | "ms": { 91 | "version": "2.0.0", 92 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 93 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 94 | }, 95 | "nexmo": { 96 | "version": "2.0.2", 97 | "resolved": "https://registry.npmjs.org/nexmo/-/nexmo-2.0.2.tgz", 98 | "integrity": "sha1-Flsgr3sKVmiQcUt+v1O+ZF8Flv0=", 99 | "requires": { 100 | "jsonwebtoken": "7.4.3", 101 | "uuid": "2.0.3" 102 | } 103 | }, 104 | "safe-buffer": { 105 | "version": "5.1.1", 106 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 107 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 108 | }, 109 | "topo": { 110 | "version": "1.1.0", 111 | "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", 112 | "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", 113 | "requires": { 114 | "hoek": "2.16.3" 115 | } 116 | }, 117 | "uuid": { 118 | "version": "2.0.3", 119 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", 120 | "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" 121 | }, 122 | "xtend": { 123 | "version": "4.0.1", 124 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 125 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-simple-api", 3 | "version": "0.0.5", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "dev": "nodemon server.js", 8 | "start": "node server.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "body-parser": "^1.15.2", 15 | "express": "^4.14.0", 16 | "helmet": "^3.1.0", 17 | "morgan": "^1.7.0" 18 | }, 19 | "devDependencies": { 20 | "flightplan": "^0.6.15", 21 | "fly": "^2.0.4", 22 | "nodemon": "^1.12.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /routes/helloWorld.js: -------------------------------------------------------------------------------- 1 | let express = require('express'); 2 | let router = express.Router(); 3 | 4 | let HelloWorldController = require('../controllers/helloWorld.js'); 5 | 6 | // .get is a method which 'sits' on HelloWorldController 7 | // for more check controllers/helloWorld.js 8 | router.get('/hello', HelloWorldController.get); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | let express = require('express'); 2 | let path = require('path'); 3 | let bodyParser = require('body-parser'); 4 | let morgan = require('morgan'); 5 | let helmet = require('helmet'); 6 | let config = require('./config.js'); 7 | let app = express() 8 | 9 | let port = config.PORT || '5000'; 10 | let API_BASE = config.API_BASE; 11 | let helloWorld = require('./routes/helloWorld.js'); 12 | 13 | app.use(function(req, res, next) { 14 | res.setHeader("Access-Control-Allow-Origin", "*"); 15 | res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); 16 | res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 17 | next(); 18 | }); 19 | app.use(helmet()); 20 | app.use(morgan('dev')); 21 | app.use(bodyParser.json()); 22 | app.use(bodyParser.urlencoded({ 23 | extended: false 24 | })); 25 | 26 | app.use(API_BASE, helloWorld); 27 | 28 | app.listen(port, function() { 29 | console.log('express-simple is running on port ', port); 30 | }); 31 | --------------------------------------------------------------------------------