Using NodeJS as a Rest API and a WebSocket server


10.17.15 Posted in Technology by

What is REST?

REST stands for Representational State Transfer. (It is sometimes spelled “ReST”.) It relies on a stateless, client-server, cacheable communications protocol — and in virtually all cases, the HTTP protocol is used.

REST is an architecture style for designing networked applications. The idea is that, rather than using complex mechanisms such as CORBA, RPC or SOAP to connect between machines, simple HTTP is used to make calls between machines.

In many ways, the World Wide Web itself, based on HTTP, can be viewed as a REST-based architecture.

RESTful applications use HTTP requests to post data (create and/or update), read data (e.g., make queries), and delete data. Thus, REST uses HTTP for all four CRUD (Create/Read/Update/Delete) operations.

What is NodeJS?

Node.js is a very powerful JavaScript-based framework/platform built on Google Chrome’s JavaScript V8 Engine. It is used to develop I/O intensive web applications like video streaming sites, single-page applications, and other web applications. Node.js is open source, completely free, and used by thousands of developers around the world.

What is WebSocket?

WebSocket is an advanced technology that makes it possible to open an interactive communication session between the user’s browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.

Requirement

NodeJS is installed. See installation instructions on MAC by Dave McFarland.

Objective

A web-based interactive system is integrated with a peripheral device. To facilitate POST data transmitted by the device, REST API is  built using NodeJS. Due to interactivity needs, the NodeJS script also calls a REST API of the web-based system and broadcast response data via websockets. Thus NodeJS serves as the middleware between the peripheral device and the web-based system.

Getting Started

We will need to define our Node packages in package.json.

{
  "name": "node-api",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node api"
  },
  "dependencies": {
    "express": "*",
    "body-parser": "*",
    "querystring": "*",
    "sockjs": "*"
  }
}

What do these packages do?
express allows us to set up middlewares to respond to HTTP Requests and define routes which are used to perform different action based on HTTP Method and URL.
body-parser lets us pull POST content from our HTTP request so that we can do things.
querystring allows us to produce a JSON-formatted string from whatever data object was passed in.
sockJS is a Javascript library that provides a WebSocket-like object, allows us to transmit data to client for additional user interactivity.

Installing our Node Packages

$ npm install

Running this in the commandline in the root of our project pulls in all the packages defined into a node_modules folder in our project.

npm is Node’s package manager that will bring in all the packages we defined in package.json

Start server

// node-api.js
// BASE SETUP
// =============================================================================

// call the packages we need
var express    = require('express');        // call express
var app        = express();                 // define our app using express
var bodyParser = require('body-parser');    //call body-parser

var http = require('http')                  //call http
  , sock = require('sockjs');               //call sockjs

var querystring = require('querystring');   //call querystring
var host = 'external-api.host';             //set host of external API
var websocketport = 1337;                   //set websocket port
var env_port = 8080;                        //set api port

// WEBSOCKETS
// =============================================================================
/*
* Store all connected clients
*/
 
var sockets = {};

/*
* Create websockets server and attach listeners
*/
 
var socketServer = sock.createServer();
 
socketServer.on('connection', function(conn) {
        sockets[conn.id] = conn;
    
});


var httpServer =  http.createServer().listen(websocketport);

/*
* Hook websockets in to http server
*/
 
socketServer.installHandlers(httpServer, { prefix: '/websockets' });


// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

var port = process.env.PORT || env_port;        // set our port

// ROUTES FOR OUR API
// =============================================================================
var router = express.Router();              // get an instance of the express Router

// middleware to use for all requests
router.use(function(req, res, next) {
    next(); // make sure we go to the next routes and don't stop here
});


// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
    console.log('API is working!');
});


router.route('/member')
// receive member data via POST method (accessed at POST http://localhost:8080/api/member)
.post(function(req, res) {
          // RELAY DATA TO EXTERNAL API
          // =============================================================================
          performRequest('/member', 'POST', { 
          //relay member data to http://external-api.host/member, external API via POST method
            Email: req.body.email,
            FirstName: req.body.first_name,
            Surname: req.body.surname
          }, function(data) {
              var dataString = JSON.stringify(data);
              for (var id in sockets) {
                sockets[id].write(dataString); //transmit data to websocket clients
              }
          }); 

});


// more routes for our API will happen here
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);

// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Now listening to port ' + port);

//CALL EXTERNAL API
// =============================================================================
function performRequest(endpoint, method, data, success ) {
  
  var dataString = JSON.stringify(data);
  var headers = {};
  
  if (method == 'GET') {
    endpoint += '?' + querystring.stringify(data);
  }
  else {
    headers = {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(dataString, 'utf8') 
      //Buffer.byteLength prevents accented characters like ü to be escaped
    };
    
  }

  var options = {
    host: host,
    path: endpoint,
    method: method,
    headers: headers
  };
  var req = http.request(options, function(res) {
   res.setEncoding('utf8');
    var responseString = '';

    res.on('data', function(data) {
      responseString += data;
    });
 
    res.on('end', function() {
      var responseObject = JSON.parse(responseString);
      success(responseObject);
    });
  });
 
  req.on('error', function(e) {
      console.log('error on submitting data');
  });
  
  req.write(dataString);
  req.end();
}

Base Setup In this section, we call packages we need and initialise them to variables we shall use in the script.

WebSockets We create websocket server and attach listeners

Relay Data to External API We receive POST data from the peripheral device and relay it to the API of the web-based system. We then utilise sockjs to transmit response data to websocket clients for additional user interactivity.

Routes for Our API This section will hold all of our routes. The structure for using the Express Router let’s us pull in an instance of the router. We can then define routes and then apply those routes to a root URL (in this case, API).

Start our Server We start the script to listen to the port we defined.

Call External API This function allows us to send HTTP requests to the API of the web-based sytem

Fire up the Server

Let us fire up the server!

$ node node-api.js

Run this command in the commandline where the script resides. Our script is then ready to receive POST data from our peripheral device, relays data to the API of the web-based system and then broadcast response data to websocket clients.

Broadcast to Websocket clients

In order for websockets client to listen to Websocket server, we use SockJS client javascript. This javascript is loaded in our websocket client(i.e. web browser, for example).

We add another script in our client to utilise SockJS client and let us listen to our websocket server.

    
    var sock = new SockJS(BASE_URL_OF_OUR_NODEJS_SCRIPT+':1337/websockets');
    sock.onmessage = function(e) {
        console.log(e);
        console.log(e.data);
        //do certain actions here for additional user-interactivity
    };

Conclusion

Submitting data to REST API and broadcasting to websocket clients present security loopholes. Thus implementing security measures is strongly advised. In this script, we can add authentication, using an authentication token, limiting to specific ip ranges and encrypting sensitive information.

This post assumes that you have played around with NodeJS already. Please send me an email at ezra[at]ezraundag.com if you have any questions.

Recommended Articles:
Learn REST: A Tutorial by DR. M. ELKSTEIN
Node.js Tutorial by Tutorials Point
Build a RESTful API Using Node and Express 4 by Chris Sevilleja
Simple chat application using SockJS by Trường TX
Introducing WebSockets: Bringing Sockets to the Web by Malte Ubl and Eiji Kitamura
Websockets by MDN

 



Comments are closed.