- Introduction
- Running the application
- Creating a controller
- Setting environment configs
- Contributing
- Running test
- Code coverage
- API documentation
- License
- Author
A boilerplate for REST APIs. Can also be used for server-side rendered web pages. This project strictly uses the company's JS conventions.
- Download Zip
- Extract to your project's folder
- Import
database/schema.sqlanddatabase/seed.sql
mysql -uroot < database/schema.sql
mysql -uroot < database/seed.sql- Run these commands:
npm install -g grunt-cli
npm install
grunt #or npm run dev-server- check http://localhost:<config.app.PORT>
- Update package.json details
- Update config/config.js
- Don't forget to pull
Controllers are the heart of your application, as they determine how HTTP requests should be handled. They are located at the controllers folder. They are not automatically routed. You must explicitly route them in config/router.js. Using sub-folders for file organization is allowed.
Here's a typical controller:
// user.js
require('app-module-path/register');
const util = require('../helpers/util');
const mysql = require('anytv-node-mysql');
const squel = require('squel');
const moment = require('moment');
exports.update_user = (req, res, next) => {
const data = util.get_data(
{
user_id: '',
_first_name: '',
_last_name: ''
},
req.body
);
function start () {
let id;
if (data instanceof Error) {
return res.warn(400, {message: data.message});
}
id = data.user_id;
delete data.user_id;
const query = squel.update()
.table('users')
.setFields(data)
.where('user_id = ?', id)
.limit(1);
mysql.use('my_db')
.squel(query, send_response)
.end();
}
function send_response (err, result) {
if (err) {
return next(err);
}
res.send({ message: 'User successfully updated' });
}
start();
};
exports.delete_user = (req, res, next) => {
...Detailed explanation:
require('app-module-path/register');
const util = require('../helpers/util');
const mysql = require('anytv-node-mysql');
const squel = require('squel');
const moment = require('moment');- The first part of the controller contains the helpers, and libraries to be used by the controller's functions
- The
app-module-path/registermodule prevents the usage of__dirnamein requiring local modules - Notice the order of imported files, local files first followed by 3rd-party libraries
- This block should always be followed by at least one new line to separate them visually easily
exports.update_user = (req, res, next) => {- snake_case on exported function names
reqis an object from express, it contains user's requestresalso an object from express, use this object to respond to the requestnexta function from express, use this to pass to the next middleware which is the error handler
const data = util.get_data(
{
user_id: '',
_first_name: '',
_last_name: ''
},
req.body
),- it is common to use
dataas the variable to store the parameters given by the user util.get_datahelps on filtering the request payload- putting an underscore as first character makes it optional
- non-function variables are also declared first
- new line after non-function variables to make it more readable
function start () {
let id;
if (data instanceof Error) {
return res.warn(400, {message: data.message});
}
id = data.id;
delete data.id;
const query = squel.update()
.table('users')
.setFields(data)
.where('user_id = ?', id)
.limit(1);
mysql.use('my_db')
.squel(query, send_response)
.end();
}startfunction is required for uniformity- the idea is to have the code be readable like a book, from top-to-bottom
- since variables are declared first and functions are assigned to variables, we thought of having
startfunction to denote the start of the process - as much as possible, there should be no more named functions inside this level except for
forEach,map,filter, andreduce. If lodash is available, use it.
function send_response (err, result) {
if (err) {
return next(err);
}
res.send({ message: 'User successfully updated' });
}
start();send_responseis common to be the last function to be executed- use
nextfor passing server fault errors - after all variable and function declarations, call
start
Notes:
- use
res.warn(status, obj)orres.warn(obj)instead ofnext(error)if the error is caused by the API caller
The default configuration uses development. Any changes on the files inside that folder will be ignored.
If you want your config to be added on the repo permanently, add it on config.js.
Just make sure that it's not confidential.
production is a dedicated config folder for the production environment. Use it via setting $NODE_ENV to production
export NODE_ENV=productionInstall the tools needed:
npm install istanbul -g
npm install apidoc -g
npm install mocha -g
npm install --only=dev- Please take a look at Production Config Cleanup Guide
- For production config, it should be added as a submodule.
git submodule add -b <branch> <https repository> config/env/production- Whenever there are changes in production, you should update the submodule too.
git submodule init
git submodule foreach git pullnpm test
# or
grunt test- Use npm scripts or grunt tasks that watches the tests.
npm run dev-tests
# or
grunt dev-testsnpm run coverageThen open coverage/lcov-report/index.html.
npm run docsThen open apidoc/index.html.
MIT