How to Write a REST API Class for Node.js

While implementing an API with Node.js, it is better to write it as a class, create a module, and import the module in the main Node.js script.

This tutorial will tell how to :

  • Implement each API call as a function, where it returns a Promise. The returned Promise will get resolved when the API call is successful, otherwise it will get rejected
  • All implemented API functions are put down under a single Javascript class
  • The class is implemented as Node.js module which can be imported through require

For an overview of Javascript Promises you can refer to this article. For Javascript Classes you can refer to this article.

The below codes are explained through a demo non-existent API. It returns some JSON data as response. Also if the API call fails, an "error" object is returned.

Handling Asynchronous API Calls with Promises

An API call is nothing but sending a HTTP request to a server. With Node.js, it can be implemented with the HTTP or HTTPS module.

Assuming a GET request, a Javascript function implementing it will look something like :

/* ATTEMPT 1 */

function user_api(api_parameter) {
	const api_url = 'http://demo-api-server.com/api?parameter=' + api_parameter;

	// http is the object returned by the http module (referenced somewhere in the code)
	const api_call = http.get(api_url, function(api_res) { 
		let body_chunks = [];
	  	api_res.on('data', function(chunk) {
			body_chunks.push(chunk);
	  	});

	  	api_res.on('end', function() {
			let body = Buffer.concat(body_chunks);
			body = JSON.parse(body); // assuming API sends a JSON response

			// assuming API sends an "error" object in response if it fails
			if('error' in body)
				console.log(body.error);
			// success
			else
				console.log(body);
	  	});
	});

	// error
	api_call.on('error', function(e) { 
		console.log(e.message);
	});
}

Since we want the response from the API to be returned back, as in synchronous style, we return a Promise. If the API call is successful, this Promise will be resolved passing the API response. If the API fails, the Promise is rejected passing an error message.

/* ATTEMPT 2 */

function user_api(api_parameter) {
	return new Promise(function(resolve, reject) {
		const api_url = 'http://demo-api-server.com/api?parameter=' + api_parameter;

		const api_call = http.get(api_url, function(api_res) { 
			let body_chunks = [];
		  	api_res.on('data', function(chunk) {
				body_chunks.push(chunk);
		  	});

		  	api_res.on('end', function() {
				let body = Buffer.concat(body_chunks);
				body = JSON.parse(body);

				if('error' in body)
					reject(body.error);
				else
					resolve(body);
		  	});
		});

		api_call.on('error', function(e) { 
			reject(e.message);
		});
	});
}

Writing a Javascript Class

Like in synchronous style code, we want a class wrapping all API calls as methods. So we write down a Javascript class with its methods.

/* ATTEMPT 3 */

class UserApiClass
{
	// pass the main http object while creating an object
	constructor(http) {
		this.http = http;
	}

	user_api(api_parameter) {
		// http refers to the member variable of the class
		// which refers to the main http object that creates the Node.js server
		const http = this.http;

		return new Promise(function(resolve, reject) {
			const api_url = 'http://demo-api-server.com/api?parameter=' + api_parameter;

			const api_call = http.get(api_url, function(api_res) { 
				let body_chunks = [];
			  	api_res.on('data', function(chunk) {
					body_chunks.push(chunk);
			  	});

			  	api_res.on('end', function() {
					let body = Buffer.concat(body_chunks);
					body = JSON.parse(body);

					if('error' in body)
						reject(body.error);
					else
						resolve(body);
			  	});
			});

			api_call.on('error', function(e) { 
				reject(e.message);
			});
		});
	}
}

Please note that we have passed the http (or https) object in the class' constructor. This is the same object returned by the http (or https) module while creating a Node.js server. So basically the same http object that is used in the main Node.js file, implements the API calls too.

var http = require('http');

http.createServer(function(req, res) {
	// server started
}).listen(8080); 

Implementing the API Class as a Node.js Module

To keep things clean, we create a separate file for the API class, and create a module. To use the API in a main Node.js file, we can require the module.

/* FINAL MODULE */

// codes saved in a separate file "user-api.js"

class UserApiClass
{
	constructor(http) {
		this.http = http;
	}

	user_api(api_parameter) {
		const http = this.http;

		return new Promise(function(resolve, reject) {
			const api_url = 'http://demo-api-server.com/api?parameter=' + api_parameter;

			const api_call = http.get(api_url, function(api_res) { 
				let body_chunks = [];
			  	api_res.on('data', function(chunk) {
					body_chunks.push(chunk);
			  	});

			  	api_res.on('end', function() {
					let body = Buffer.concat(body_chunks);
					body = JSON.parse(body);

					if('error' in body)
						reject(body.error);
					else
						resolve(body);
			  	});
			});

			api_call.on('error', function(e) { 
				reject(e.message);
			});
		});
	}
}

module.exports = UserApiClass;

Using the Module in the Main Node.js Script

Now that the API class is ready, and implemented as a module, we can now use it in the main Node.js file. We can import the module, create an object of the class, and call the appropriate method for an API request.

// http object (that creates the Node.js server)
const http = require('http');

// import the API module
const UserApiClass = require('./user-api');

// just as demo, api object is created on server start 
// for real cases an object will be created when a specific route is requested
http.createServer(function(req, res) {
	// create an object of UserApiClass
	const api_ob = new UserApiClass(http);

	// some parameter for API call
	const parameter = 10;

	// call the API
	api_ob.user_api(parameter)
		.then(function(data) {
			// API call successful
			console.log(data);
		})
		.catch(function(error) {
			// API call failed
			console.log(error);
		});
}).listen(8080); 

Conclusion

Writing a set of APIs as a class, implemented in a Node.js module will keep things clean. Although the tutorial explained the concepts for a demo API call, the same concepts can be applied to any API service.