Integrating NodeJS server into an Ionic Application

What do you do if your application needs to pull in data from an external source, store data externally, share data with other users or needs to authenticate i.e. anything related to outside world? Answer is you will need to use any kind of back-end or server-side code. And for the same reason in this post, we are going to discuss about the integration of NodeJS server into an ionic application.

When your application is integrated with backend, the application will be communicating with the some server on the Internet that will acts as the go-between the application and any external service it needs to interact with(like a remote database).
There are many back-end services like Firebase, but as i like to prefer NodeJS is one of the most popular back-end when it comes to Ionic applications.The popularity of NodeJS as a back-end technology is at least partly due to the fact that it allows you to write your back-end with JavaScript as well which is overwhelming and comfortable for the developers as they don’t have to learn any new language to operate.

Prerequisite

NodeJS and Ionic should already be installed in your system. If you want to learn how to install ionic and NodeJS in your system just follow-up our previous post i.e. Full Ionic Framework Setup In Ubuntu Step-by-step tutorial.
This will help you in step-by-step guidance of installation of Ionic and NodeJS.
And now for some knowledge of ionic and NodeJS, I am going to spend a bit time explaining about ionic and node basics.

NodeJS

NodeJS is a server-side platform built on Google Chrome’s JavaScript Engine (V8 Engine). NodeJS is a JavaScript run-time which you can use on a server to run JavaScript code. This enables front end developers to create web services using JavaScript.
NodeJS eliminates the waiting, and simply continues with the next request. NodeJS also provides a rich library of various JavaScript modules which simplifies the development of web applications using NodeJS to a great extent.
NodeJS uses an event-driven, single-threaded, non-blocking I/O model that makes it light-weight and efficient, perfect for data-intensive real-time application that runs across distributed devices.

Project Structure

Ionic front-end and NodeJS backed are two separate entities so the management of project structure is important.
You should create two different folders inside a folder, one for NodeJS back-end code and another for ionic front-end code.

Create a folder named ion-node

create a folder inside ion-node called backEnd to hold your NodeJS server

generate a new ionic application insde ion-node called frontEnd

we are doing that because you should not put the server.js file in ionic project directory.

NodeJS server

To start a new NodeJS server you have to run only one command which will first of all create your package.json. Afterwards we install the needed npm packages.

:~/ion-node/backEnd$ npm init

While the npm creation runs you will get asked many questions. Most of them can be skipped by pressing enter using the default value, but make sure to set the entry point of your app to server.js. Of course you can change it later inside the package.json, but why not do it right in the first place here.

Your package.json file should now look like this:

 
 {
   "name": "my-app",
   "version": "1.0.0",
   "description": "demo server",
   "engines": {
   "node": "8.9.1"
   },
   "main": "server.js",
   "scripts": {
   "start": "node server.js"
 },
  "author": "",
  "license": "ISC",
  "dependencies": {
  "body-parser": "^1.18.2",
  "cors": "^2.8.4",
  "del": "^3.0.0",
  "express": "^4.16.2",
  "http": "0.0.0",
  "method-override": "^2.3.10",
  "morgan": "^1.9.0"
 }
 }

One important part of this package.json is that it defines the “start” script to be run. To start this server, the node server.js command must be run, because the file that contains our server code is called server.js. To run the server locally, you would first need to install any dependencies by running:

npm install

These are some attributes of Package.json:

  • Name − name of the package
  • Version − version of the package
  • Description − description of the package
  • Homepage − homepage of the package
  • Author − author of the package
  • Contributors − name of the contributors to the package
  • Dependencies − list of dependencies. NPM automatically installs all the dependencies mentioned here in the node_module folder of the package.
  • Repository − repository type and URL of the package
  • Main − entry point of the package
  • Keywords − keywords

now run the following command inside of the backEnd folder

npm install --save body-parser cors del express method-override morgan

now setting up the template for server.js

 var express = require('express');
 var bodyParser = require('body-parser');
 var logger = require('morgan');
 var methodOverride = require('method-override')
 var cors = require('cors');

var app = express();
 app.use(logger('dev'));
 app.use(bodyParser.json());
 app.use(methodOverride());
 app.use(cors());

app.post('/details',function(req, res){
 });

app.listen(process.env.PORT || 8081);

In the above code we are setting up the a few variables to hold reference to the various packages, we use require instead of import because we are using ES5 JavaScript here.

These packages are as follows:

  • Body-parser:  To handle HTTP POST request in Express.js version 4 and above, you need to install middleware module called body-parser.
    Body-parser extract the entire body portion of an incoming request stream and exposes it on req.body. The middleware was a part of Express.js earlier but now you have to install it separately. This body-parser module parse the JSON, buffer, string and URL encoded data submitted using HTTP POST request.
  •  Method-override: The methodOverride() middleware is for requests from clients that only natively support simple verbs like GET and POST. So in those cases you could specify a special query field (or a hidden form field for example) that indicates the real verb to use instead of what was originally sent. That way your backend .put()/.delete()/.patch()/etc. routes don’t have to change and will still work and you can accept requests from all kinds of clients.
  • Morgan: Morgan is basically a logger, on any requests being made,it generates logs automatically. It outputs useful debugging messages.
  • CORS (Cross Origin Resource Sharing): CORS exists for security reasons and to limit which resources a browser can gain access to, from another website. If we try an AJAX/xmlhttprequest to a file like that, we get an error message from the console in our browser.
    The CORS rules apply to the same hostname and are also bound to the same port. If you only want to serve some routes to clients of all origins, you should set the res.headers specifically for these routes and omit the next(), but just send your response.
  • Express: Express is a minimal and flexible NodeJS web application framework that provides a robust set of features to develop web and mobile applications. It facilitates the rapid development of Node based Web applications. It allows to set up middlewares to respond to HTTP Requests. It defines a routing table which is used to perform different actions based on HTTP Method and URL.
    Here we created a new express application and then we setup our various packages on that application.

Now we can ask the server to start listening for request by calling the listen method. And whatever is a PORT environment variable defined it will start listening to request otherwise the server will start listening for request on port 8080 by default.

Now you just need to run the following command

node server.js

and the server would start running locally that means you could access it over

http://localhost:8081/

Creating Routes and Making Requests

we have created a working NodeJS server but the server only wouldn’t do anything with the requests yet so it doesn’t provide any responses.
The way that we would integrate NodeJS server into Ionic application is for Ionic Application to make HTTP requests to the server. Our Ionic application might make a request to:

 this.http.get('http://localhost:8081/details').map(res =>    res.json()).subscribe(data => {
   console.log(data);
 });

We are making a request to the /posts route and then we would expect that the server give us some useful information in the response. So, we need to set up these “routes” on our server that our application can make requests to, and we can do that using Express.
To set up a route in a NodeJS application that is using Express, all we need to do is this:

var express = require('express');
 var bodyParser = require('body-parser');
 var logger = require('morgan');
 var methodOverride = require('method-override')
 var cors = require('cors');

var app = express();
 app.use(logger('dev'));
 app.use(bodyParser.json());
 app.use(methodOverride());
 app.use(cors());

app.get('/details', function(req, res) {

console.log("details!");

});

app.listen(process.env.PORT || 8081);

If you wanted to handle a POST request instead of a GET request you would do this instead:

app.post('/details',function(req, res) {

res.json({"success":true});

});

we are going to create the requests that we want to send to our NodeJS server from our Ionic application. We will set up a form that allows us to enter a name, and some code to handle sending the results to the server.

Modify src/pages/home/home.html to reflect the following:

<ion-content padding>
 <ion-item *ngIf="isLoggedIn; else loginTemplate">
 <ion-item><h2>{{responseData}}</h2></ion-item>
 <button ion-button primary (click)="back()">Back</button>
 </ion-item>
 <ng-template #loginTemplate>
 <ion-item>
 <ion-label floating>Enter your name...</ion-label>
 <ion-input [(ngModel)]="name" type="text"></ion-input>
 </ion-item>
 <button ion-button primary (click)="Show()">Show</button>
 </ng-template>
</ion-content>

Modify src/pages/home/home.ts to reflect the following:

import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { NavController } from 'ionic-angular';
import { map } from 'rxjs/operators';

@Component({
 selector: 'page-home',
 templateUrl: 'home.html'
})
export class HomePage {
 userData: any;
 responseData;
 name: string;
 isLoggedIn:boolean = false;

constructor(private http: Http) {
 }
 back(){
  this.isLoggedIn = false;
  localStorage.clear();
 }

details() {
let data = {
 name: this.name
 };
 this.http.post('http://192.168.1.2:8081/details', data).pipe(
  map(res => res.json())
  ).subscribe(response => {
   console.log('POST Response:', response);
 });

 this.http.get('http://192.168.1.2:8081/details/' + this.name).pipe(
 map(res => res.json())
 ).subscribe(response => {
  console.log('GET Response:', response);
  this.responseData=response;
  window.localStorage.setItem('userData',JSON.stringify(response));
  this.isLoggedIn = true;
 });
 }
}

we are making two separate requests here. Once we click the ‘Show’ button We make a POST request to / details that will POST the data entered to the server. We also make a GET request that appends the data entered onto the end of the URL instead of POSTing the data. As you will see in a moment, we can actually set up multiple instances of the same route to handle different methods.

We are expecting to get a JSON response in return, and we log that out to the console.

Sending Response to Ionic

/ion-node/backEnd/server.js

var express = require('express');
var bodyParser = require('body-parser');
var logger = require('morgan');
var methodOverride = require('method-override')
var cors = require('cors');

var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(cors());

app.post('/details', function(req, res){
 if(req.body.name.toLowerCase() === 'demo'){
 res.status(401).send({message: 'Sorry, no demo's!'});
 } else {
 res.send({
 passed: true,
 message: 'Welcome, friend!'
 });
 }
});

app.get('/details/:name', function(req, res){
 console.log("data called1");
 if(req.params.name.toLowerCase() === 'demo'){
 res.status(401).send({message: 'Sorry, no demo\'s!'});
 } else {
 res.json('Welcome'+' '+req.params.name);
 }
});

app.listen(process.env.PORT || 8081, function () {
 console.log('Example app listening on port 8081!');
});

In the code above, we have a route to handle our POST requests to /details and we also have a route to handle our GET requests to /details. In the POST route, we are able to access the data that is sent from our Ionic application through req.body.name. The GET route is a little different because we are supplying the data directly to the URL endpoint that is being hit. If we define a route that defines parameters using a colon like this:

 /details/:myvalue

and then we hit the following URL

http://localhost:8081/details/himasnhu

In both cases, we convert the supplied value to lowercase and see if it is equal to “demo”. If it is, we set the HTTP status to 401, which is the “Unauthorised” error code (you don’t have to do this, but it’s a good idea to provide useful status codes), and then in the POST route we send a response to the Ionic application by using the send method. If the name is not equal to “demo”, then we send a JSON object back that includes a message.
The GET route is very similar, except rather than using res.send we use res.json. These methods are mostly identical, and will both send a response back to the Ionic application, but the benefit of using res.json is that it will format any data supplied as valid JSON data (even if we just supply a simple string like ‘Welcome!’).

Our Ionic application and server should now be working as intended. If you run your server in the terminal using:

npm start

and you also run your Ionic application using another terminal instance.

Leave a Reply

Your email address will not be published. Required fields are marked *