- 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.sql
anddatabase/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/register
module prevents the usage of__dirname
in 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
req
is an object from express, it contains user's requestres
also an object from express, use this object to respond to the requestnext
a 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
data
as the variable to store the parameters given by the user util.get_data
helps 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();
}
start
function 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
start
function 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_response
is common to be the last function to be executed- use
next
for 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=production
Install 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 pull
npm test
# or
grunt test
- Use npm scripts or grunt tasks that watches the tests.
npm run dev-tests
# or
grunt dev-tests
npm run coverage
Then open coverage/lcov-report/index.html
.
npm run docs
Then open apidoc/index.html
.
MIT