Ionic Restify MongoDB – An End to End Hybrid App20 min read

Ionic Restify MongoDB – An End to End Hybrid App

Build the same Bucket List app without worrying about server side code, check out Creating a Firebase Powered End to End Ionic Application

In this post, we are going to build an End to End Hybrid App, that has a server component and a client component. Our server will be built on top of Node js, with Restify as the server side framework and MongoDB as the data persistence layer. Our Client is a Hybrid App, built with Ionic framework. We then are going to deploy the Ionic app using PhoneGap Build service to generate a Native installer.

The App we are going to build is a Bucket List app. Here a user can register and login. Then s/he can create a few bucket list items. Which would eventually result in

2014-04-27-12-42-23 2014-04-27-12-42-32

2014-04-27-12-44-31 2014-04-27-12-46-08

  2014-04-27-12-46-37 2014-04-27-12-43-37

These images are taken from my Android Samsung Galaxy Note I device. And the performance was okay. But there is a lot of scope for improvement. If you want to dig into the app yourself, click here.

I have deployed the REST server on Heroku, DB on MongoLab and the client is the Ionic PhoneGap Native app!

List of all the REST service endpoints can be found here (needs some cleanup).

If you want to issue a PhoneGap build before diving in, you can fork this repo and submit it here. Download the installer and test it out. Or you can download the installer directly from here.

You can find the complete code here.

Contents

Application Architecture

The first and foremost thing we are going to look at is the End to End Architecture. BucketListApp

The above Image should give you an idea as where we are headed. At a very high level, we have 3 layers (Three Tier Architecture Duh!). The Database Layer served by MongoDB, The REST Server, fulfilled by Node js & Restify and finally the client layer, well practically this can be any device that can consume a REST endpoint. In our case it is a Ionic PhoneGap application.

Database Layer

I have chosen MongoDB as the backed database because its stores JSON documents and is very simple to interact with among other things. Our Database will have 2 collections.

appUsers – For registering and authenticating the users

bucketLists – To maintain BucketsList items created by each registered user.

We will be doing the development on a local instance of MongoDB and the migrating the same to MongoLab or any other MongoDB as a Service.

REST Service Layer

This is the brain of our entire concept. i.e. the BucketList app. This layer takes in a request, depending on the request it will hit the database and dispatch the requested data, if the user is authenticated.

We will be using Node js server for hosting the service. The REST endpoints will be configured using Restify, a Node js Package to handle REST services. We will also use Mongojs, a Node js Package to manage the DB interactions. If you are new to this environment, I strongly recommend you to take at look at this.

The next key component in our REST service is authentication. As you already know REST is stateless. i.e. It does not remember the client from which the request has originated. In our application, we have a concept very similar to an OAuth, where the client is expected to send a token, that it was issued when the client made the first interaction with the server.

In our application, there is no Authentication or Authorization to access the Register and Login REST endpoints. But when the client needs any data, it needs to send the logged in user’ email as a token, so that we know if the client is trustable (Just a simple workaround for the server. I didn’t want to implement the complete she bang! of OAuth for this post).

Client Layer

With the ever rising demand of utilizing popular skills like web development to do practically any form of development made me pick a Hybrid App as my client. We are going to use Ionic Framework as the face of our Hybrid App. Primarily because of its tight integration with Angularjs, making consuming web services like our BucketList API a walk in the park which is full of REST services.

Quite a mouthful that last paragraph.

The client will have 5 primary Angular controllers.

1. Sign Up : Register a new User

2. Sign In : Login an existing user

3. Show Bucket List : To show all the incomplete bucket list items

4. Show Completed List : To show all the completed bucket list items

5. Create new Item : To create a new bucket list item

Apart from the above, we have a couple of methods to mark an item completed and delete an item.

We will be using localStorage to manage the session on the device. And a few other Ionic-Angular directives to make the app more interesting.

Prerequisites

Now that we have an idea of what we are going to do, lets get started. There are a few prerequisites that we need to be aware of before we begin development.

Server Layer

You need to have an understanding of Node js, Restify and Mongojs to write good server code. You can find a post here, that will teach you to write a REST API using the above mentioned components. You can also find a quick tutorial of MongoDB here.

Client Layer

You need to be familiar with PhoneGap, PhoneGap build, GitHub & Ionic Framework. You can find a post on Git here, PhoneGap here, how to set it up here and a quick tutorial on Ionic Framework and PhoneGap build here. You need to be familiar with Angularjs too to get a hang of Ionic, you can find a hands on tutorial here.

If you are comfortable with these, you can get rolling with the development.

Begin Development

First, lets create a new folder named bucketList. Generally, when I develop, I like to keep the dev code separate from the prod. This is more from a manageability perspective. Create 2 folders dev and prod inside the bucketList folder.

We will create 2 more folders inside the dev folder named server and client. Our final structure will be

Screen Shot 2014-04-27 at 7.06.21 pm

Server Side Development

We are going to start off the server side development first. We will be dealing with a local instance of MongoDB for the local development. If you have completed the prerequisites, you would already have MongoDB installed. Open a new terminal/prompt and start the MongoDB service by running

mongod

Next to build the server layer, Navigate to dev/server folder. First we will create a new node project. Open terminal/prompt here and run

npm init

Feel free to fill it up as you please. Next we are going to install the project dependencies. There are 3 key dependencies

1. mongojs

2. restify

3. bcrypt

4. morgan (optional – for logging)

Run

npm install --save mongojs restify bcrypt morgan

And the required dependencies will be installed. The completed package.json would be

Do notice that I have also added the engine details too. This will be used when we deploy the app to Heroku.

Next, create a new file named server.js inside the dev/server folder. This will be the starting point of our application. Create 2 more folders named auth and list here. All the code related to user interaction will be present inside the auth folder and all the BucketList API inside the list folder. This way, we can keep the code more organized and decoupled.

Our server.js will be

We require all the dependencies. And the mongojs is configured to use a local database named bucketlistapp. Lines 7 to 10 configures the Restify middleware to take care of parsing the request and logging. Lines 13 to 18 are very critical for a REST service. This is the place where we allow CORS (Cross Origin Request Sharing). i.e. any web based client can access our resources. They need not be from the same domain as ours. Without this, your client’s will not be able to talk to the server.Finally on Line 20, we start the server.

Next, lets take a look at the user registration and login. Before we start working on it, we need to have a system in place to store the passwords. We do not want to store the password as plain text in our DB. Create a new file inside the auth folder named managePasswords.js, and add the below code

There are 2 methods here. One for encrypting the password used while registering with the application and the other for comparing the passwords during login process. Simple?

Next, we will write our API for managing the users. Create a new file named manageUser.js inside the auth folder. Add the below contents to it

Things to notice, Line 3, we are exporting this file as a module, which we will add into server.js soon. We get the server instance and the db instance from server.js. Line 5, we make the email field of the user collection a unique index. Also do notice that our password manager methods are async as any other node code. So, we are going to nest our logic in the success callback of password creation method on line 13. The same goes for password comparison on line 54. Do notice that we set appropriate HTTP status code on lines 19, 28, 42, 57 and 64 while dispatching the response.

The logic for login and register is pretty straight forward. We have a couple of checks to validate the data & then dispatch the results to the client.

Next, add the below line of code to server.js

var manageUsers = require('./auth/manageUser')(server, db);

and start the server by running

node server.js  or  nodemon server.js

You can use curl or chrome’s Advance REST client or Postman to register and login. Your request should be something like

Screen Shot 2014-04-27 at 7.51.41 pm

And then, you can hit the login end point with the created email and password to verify the service. Easy right?

Next up, we are going to build services that will let the client interact with BucketList API. Before we let a client interact with the API, we want to authenticate the incoming request and authorize if the client can access the API. For that, we will write a simple validator.

Create a new file named validateRequest.js inside the auth folder. And paste the below contents into it

Things to note, Line 11 checks if there is a token param present or not. If not, we will dispatch a 403, with a proper error message. If the request does have a token param, we will validate if the email in the token is valid on line 22, with the help of method on line 1. If everything is fine, we fire a callback to take the request ahead, else close it with a 403.

I know, this is not a foolproof system. If you know a email address you can try fetching the data related to that user. But since this is an example, it will work. But incase you want to adopt a system like this, I seriously recommend using a proper oAuth system in place.

Finally, we will develop the BucketList API. Create a new file inside the list folder named manageList.js and copy the below contents.

Yep, all the REST methods. GET POST PUT DELETE. As you have already noticed, we are exporting this also as a module, to be used in server.js. The first line in every method goes to validateRequest module. If this are good, the callback will be called, which would invoke the code inside the anonymous function.

Add the below line to server.js

var manageLists =   require('./list/manageList')(server, db);

Save all the flies and restart the server. Test all your endpoints like we did earlier for the Auth. You can refer to the complete API here.

This wraps up our server code. Easy Peasy right? You can add a few more collections and build their API by simply copy pasting the manageList.js file and updating the DB details.

Client Side Development

Our client is going to be a Hybrid App, built on IonicFramework & then we will build the native installer by running it through the PhoneGap build.

Now, cd back and into the client folder inside the dev. We will scaffold the IonicApp here. First we need to install IonicFramework on our local. Inside the terminal/prompt run

Windows Mac/*nix
npm install -g cordova ionic    sudo npm install -g cordova ionic

Once that is done, we will scaffold the base Ionic app inside the dev/client folder. Run

ionic start bucketListApp blank

We will use a blank template to start off. You can find other templates here. This will take a couple of minutes to scaffold the project. To run this app as is, follow this.

The scaffolded project structure would be like

Screen Shot 2014-04-27 at 8.55.14 pm

The first thing we need to do is move the config.xml into the www folder. Otherwise PhoneGap build will not recognize the app’s config. Next, we will update the config.xml with the below details, accordingly

We got the config out of our way, we will concentrate on building the App.

Our app will have 2 tabbed interfaces. The first tab interface would be between login and register. The next tab interface would be between the User’s BucketList items and completed BucketList items. You can checkout the Ionic tabs directive here.

Create a new folder inside www and name it templates. We will store all the individual screens here. Next, update www/index.html to

Things to notice, Line 15, we updated the module name, which we are going to create in soon. Lines 12, 13, we have added references to 2 script files, which we are going to create soon. Lines 16 to 20, we add a placeholder for the back button. Finally on line 21, we add a placeholder where other view would come and sit.

Quick tip: If you want to run the app, you need not emulate every time, this is a very painful process. Instead, you can host the www folder using a WAMP or LAMP or MAMP server and access the same through browser. Do not worry about the 404 on cordova.js.

Our client will be built on Ionic-Angular directives. We will have a Angular Router, that will switch templates based on the URL hash. Then the corresponding controller will be triggered. Then the controller will interact with the service layer to fetch data from our remote server’s REST API and render the view. Sounds simple?

Next, create 2 new files inside www/js folder named services.js and controller.js. app.js is where our application starts. In this file, we will create a new angular module named bucketList. Then we will add the dependencies for this module. That would be Ionic, controllers and services.

Then inside the run method, we will do some global stuff like managing the status bar etc. And then we use Angular-router to configure a few routes. Where each route will take us to a new view. The completed app.js would be

Pretty straight forward stuff.

Next, open up services.js. This is our REST API interaction layer. Here, we will add a few utility methods to the $rootScope object, like logoff or screen refresh or showing a loading message etc. And then we will return a list of API’s. The completed services.js would be

DO NOT forget to update the base variable to your local endpoint on line 3.

We are using localStorage to save the user’s email. This will be serving as a token when we interact with the REST API, as well as for the client to know if the user is logged in or not.

Next, we have the controllers.js. Here we define the functionality as what needs to be done when a particular view is triggered. We will leverage the methods from services.js to perform basic operation. You can read the file and understand what each controller does. The updated controllers.js would be

The show() , hide()  and notify()  are declared in services.js and are used to show messages to the user.

Now, lets add all the required templates to complete our client. Create the below files and content inside the templates folder

auth.html : The tab parent for the Sign In and Sign Up tabs

auth-signin.html : The tab contents of the Sign In tab

auth-signup.html : The tab contents of the Sign Up tab

 bucket.html : The parent tab container for Bucket list tabs

bucket-list.html : The tab contents to show all the bucket list items

 bucket-completed.html : The tab contents to show the completed bucket list items

And finally newItem.html : The template for creating a new Bucket List item.

I have also added a few styles inside the css/style.css, padding margin stuff.

Thats it!! we are done with the development.

Deploying the App

Its time to deploy the app, so that others can see and use it. First we are going to deploy our DB. I picked MongoLab as my hosting service. I have created a new database and updated the connection string on Line 4 in server.js.

Next, I have used Heroku to host my REST API. Before we do that, we need to make sure our code is ready to be deployed to Heroku.

Create two new folders named server and client inside the prod folder. Copy all the contents of dev/server folder except node_modules into the prod/server folder.

Then create a new file here named Procfile at the root of the prod/server folder and fill it with

This is all you need to get your project ready to push to Heroku. You can follow the remaining steps from here to continue.

Finally our client. Navigate to dev/client/bucketListApp/www/js/services.js and update the base URL on line 3, to the above Heroku server URL. Next, copy the contents of dev/client/bucketListApp/www folder to prod/client. Head to GitHub, create a new repo. Then run the following commands inside the prod/client folder

git init

git add -A

git commit -am "Initial Commit"

git remote add origin <<newly created repo url here>>

git push origin master

Once the code is pushed to the remote repo, you can submit the repo URL to PhoneGap Build here.

You can find the complete code we have developed so far here .

Thats it!! You are all done to show off your new Hybrid app.

Hope this post has given you an understanding of how to go about building a Hybrid App with your own service.


Thanks for reading! Do comment.
@arvindr21