Easy start your API with Node.JS
This article aims to provide you with a practical implementation steps towards a high performance & secure API developed on top of Node.JS.
Being a developer is not easy, especially with a hyper-energized mix of several technologies at once — Mongo, Express, Node, React, Angular, Vue, Electron, Python, PhP, Perl, C++ … and the list goes on. Not only one needs to manage equally well across a hybrid tech stack, but also you need to focus on core non-functional, system requirements. Delivering in a compressed time frame is always the unspoken project requirement. Then you factor in the globally situated teams, working across several different time zones. Think of Down South — New Zealand, and all the way upto US & Canada, and far and in between any nation, any place, any timezone. You get a good picture.
Oh, good picture reminds me of this 30,000 feet picture I clicked with my Samsung while returning to Christchurch from Auckland. This article is also like the attached image of this 30,000 feet view — high-level, crisp, clear but still complete to make sense.
Developing your own RESTful API is a daunting task in itself, but when you come across basic non-technical requirements, it becomes even more challenging because success metrics are not anymore how many lines of code — it is how the API behaves under load and under attack.
Some of the non-technical, non-functional expectations of an API are
- Deterministic: Every time the API is invoked, it must behave in exact same manner. Determinism is not about specific data; or returned results — it is about how consistently the API will respond.
- Secure: Beyond the need for a secure authentication, data in transit, whether response or request should remain out of reach for unauthorized actors.
- Not vulnerable: Don’t give in whether it is DOS, d-DOS or other type of malicious attempt at buckling API. Even under legit load, API is not supposed to cave-in.
- Performance: Respond as soon as a request comes in.
- Concurrency: Maintain a high level of concurrency to serve a larger number of user requests in parallel, without a proportional use of resources.
Node.JS is a great choice for API development. Out of the many advantages Node.JS brings forth, my top 2-favorite are:
- Quick to develop, debug & deploy
- Full support for asynchronous processing
Right — so here we begin on how to develop your RESTful APIs using Node.js.
- Install Node on your targeted environment
- Setup your DB schema. Pay attention to:
a) authentication token
b) authenticated session + expiration duration
c) refreshed authentication token
d) keep user authentication separate from user-details
e) define if API is restricted by specific countries; or maintaining white-list/black-list
3) Config.js: create the config.js file, and app_config_overrides.js
config.js file should always have complete JSON and structure for all different configuration parameters, but for sensitive key-value pairs, put only dummy values. Actual values for such sensitive data should go into app_config_overrides.js, and make sure to put the name “app_config_overrides.js” in the file .gitignore in home directory of the API.
4) Models & Controllers:
a) db.model.js: setup with a connection pool, pool manager and a singleton DB object. Anytime database object is initialized, you return the same instance again & again. Actual connection to Database should be done only when the first need to use data saved/extracted to/from database happens.
b) log.controller.js: Winston is a great choice for logging needs. API runs in the background, and therefore error-logging is very important to resolve any issues in production. You can easily redirect stdout and stderr to appropriate files which can rollover across dates.
4) Index.js: this is where you setup routes, and do the major processing.
It may look like the following:
var fs=require(“fs”);
var Promise=require(“promise”);
var express=require(“express”);
var bodyParser=require(“body-parser”);
const cfg=require(‘./config/config’); //config
const logger=require(‘./controllers/log.control’); //logger
const auth=require(‘./controllers/auth.control’); //authorization controller
const data=require(‘./controllers/data.control’); //authorization controller
const db=require(‘./models/db.model’); //main DB//setup the APP
var app=express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));app.use(‘/getDashData’, data.getDashData);
app.use(‘/doLogin’, auth.login);
app.use(‘/’, auth.login);// start server
const server = app.listen(cfg.server_env.node_port, function () {
logger.info(‘Server listening on port ‘ + cfg.server_env.node_port);
});
We are going to use “express” because it makes the development faster, and setting routes easier. You can read more about Express here:
Other than including your models, controllers, most important points to look for here is the setting up of routes.
So, if someone calls your API as https://myapi:3000/, then “/” is the default route. And it accepts any form submissions, such as GET, POST etc. Usually, it is better to restrict your API to work only with POST. This allows only form posting options for your form values — shielding them from prying eyes; and giving you additional options to provide end-to-end encryption for data in-transit [app security features — more on this later].
Routes: Inside your controller “data.control.js”, define your function with whatever name — but in the exports section, exported function name must match your specified route name. For example inside, index.js … you are specifying [app.use(‘/getDashData’, data.getDashData)], therefore in your data.control.js file, there should be a function which
a) has an exported variable name getDashData
exports.getDashData = getDashData;
b) function getDashData returns results to “res” [response] object
async function getDashData(req,res) {
// …
//Successful return
jsnRes.response=”SUCCESS”;
jsnRes.status=200;
jsnRes.msg=”Dashboard data retrieved.”;
jsnRes.data = dbRes[0];
return res.status(jsnRes.status).json(jsnRes);
} //getDashData
Finally, here’s your GIT link:
https://github.com/amarnz/restful-api-node-template
That’s all there to it.
If you wanted to take a look at setting up connection pooling, or connection preferences, here’s full code dump from GIT repository.
Let me know how you find it, and how we can together make this better for everyone.
I’ll soon come out with a basic template project in React-Native, stay tuned. To get instant notifications, please subscribe to my feed here.