Ionic Restify MongoDB – An End to End Hybrid App

Tweet about this on TwitterShare on LinkedIn8Share on Google+28Share on Reddit0Buffer this pageFlattr the authorEmail this to someonePrint this page

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

Tweet about this on TwitterShare on LinkedIn8Share on Google+28Share on Reddit0Buffer this pageFlattr the authorEmail this to someonePrint this page
  • anonymous

    Somehow I am getting erros doing the “nmp install mongojs restify bcrypt”. Also MongoDB is a bit of a bitch to install… I dont know if it working well or not Iv tried a bunch of tutorials. I made a config file, also added the shortcut to the advanced system settings. It seems I can launch it only via “mongod –dbpath [path/data/db]”. I can then connect to it with mongo from a different console. Any way of avoiding to have to specify it every time? I did the –config install thingy on smp as well.

  • Rajkumar

    Hi,
    I am getting below error, could you pelase help.

    js-bson: Failed to load c++ bson extension, using pure JS version
    J:UsersKannuDownloadsBucketListApp-masterBucketListApp-masterprodservern
    ode_modulesmongojsindex.js:494
    var p = Proxy.create({
    ^

    TypeError: Proxy.create is not a function
    at connect (J:UsersKannuDownloadsBucketListApp-masterBucketListApp-mast
    erprodservernode_modulesmongojsindex.js:494:17)

  • Apurva

    Hi
    Are you still there to reply ?

  • Raviteja Gunda

    Hi Arvind. I tried deploying the app to heroku (referring this http://thejackalofjavascript.com/deploying-node-application/ ) and when I access the https://dry-beach-6937.herokuapp.com in the browser i see this error.

    {“code”:”ResourceNotFound”,”message”:”/ does not exist”}

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hey Raviteja,

      You must have deployed the API server on to Heroku. There is no UI in that, hence the error when you fire that request. You can try accessing the REST endpoints.

      Thanks.

      • Raviteja Gunda

        I tried in another app that has UI also but still the same response. No response accessing the REST points . I will try doing it again. Thanks for the response

  • Emil Eubboline

    I get almost for everything not compatible version error while trying to install these npm packages… any ideas?

  • Nitin Singh Solanky

    Thanks @arvindravulavaru:disqus. Nice tutorial.

  • Nitin Singh Solanky

    Hi Arvind, I have done all the steps safely. But, i want to run it on local server. How can i do that ?
    Please reply asap.

    Thanks

  • Artem Pasichnyk

    Hi Arvind, thanks for a great tutorial. I’m already debugging my app on the real device, on my iPhone 5. I have stated my dev/server/server.js with nodemon and compiled the app with Xcode and ran it on my device. Now on signing in I’m having some problems: with console.log in success and error functions in my SignInCtrl it seems to log out an error, but it logs null. Waiting for your reply, thanks!

  • designscripting

    Hi Arvind,

    Thanks for the incredible tutorial and time you spent in creating this.

    I could be able to replicate the same.

    But when I try to run the client on device or emulator. The login or registration is not firing a service call. But works well in web

    Could you look in to detail: “https://github.com/designscripting/deals/” where I am missing?

    Thanks for the help.
    Saravanan B

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Saravanan. You need to add the white list plugin for this to work. This is new in Cordova. Refer : https://github.com/apache/cordova-plugin-whitelist

      Let me know if this works.

      • designscripting

        Thanks Arvind, Worked like charm :)

  • Wilson Novido

    Hi,

    Did this:
    npm install –save mongojs restify bcrypt morgan

    But I got this error:

    c:IonicbucketListdevservernode_modulesbcrypt {git}
    {lamb} if not defined npm_config_node_gyp (node “C:Userswilso_000AppDataRoamingnpmnode_modulesnpmbinnode-gyp-bin\….node_modulesnode-gypbinnode-gyp.js” rebuild ) else (rebuild)

    Building the projects in this solution one at a time. To enable parallel build, please add the “/m” switch.

    C:Program Files (x86)MSBuildMicrosoft.Cppv4.0V120Microsoft.Cpp.Platform.targets(64,5): error MSB8020: The build tools for Visual Studio 2010 (Platform Toolset = ‘v100′) cannot be found. To build using the v100 build tools, please install Visual Studio 2010 build tools. Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting “Upgrade Solution…”. [c:IonicbucketListdevservernode_modulesbcryptbuildbcrypt_lib.vcxproj]

    gyp ERR! build error
    gyp ERR! stack Error: C:Program Files (x86)MSBuild12.0binmsbuild.exe failed with exit code: 1

    Not sure how to proceed.

    Thanks,
    Wilson

  • Chitrank Dixit

    Hello Arvind very nice tutorial you have made I also read your other tutorials on phonegap, awesome work you are doing. I just want to ask you where should I host my ionic client so that I may showcase my work to employers

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello Chitrank, Thanks!

      The client is your mobile app. You need to generate Android/iOS installers and distribute it. This project is not for web hosting!

      • Chitrank Dixit

        Thanks Arvind for reply, But Just like you hosted the API on heroku. You also shared the client at this link: http://arvindr21.github.io/BucketListApp/.

        I also want to showcase my work the same way, If possible please let me know the best way to do it. Cause I have api and db server up and running at heroku and mongolab , just I need to host the client.

  • Ignacio Talavera

    Hi Arvind,first of all congratulations! 😀 very helpful and complete tutorial. I built it from the scracth following the steps, but when I run it with the latest version of the framework (1.0.0 uranum) the headers of bucket-list.html are missing. Any idea?
    Thanks!

  • Ignacio Talavera

    Very helpful tutorial, but I tried it with the latest version of ionic (uranium-unicorn1.0.0) and the header of pages like bucket-list.html are missing. Any idea? Thanks!

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Ignacio. I will look into that.

  • mcl

    Great! It helps me a lot,thank you .

  • Chitrank Dixit

    Hello Arvind , I have followed the step by step tutorial but When I use to register or signup the loading feature of ionic hangs up saying “please wait registering”, and it hangs forever.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Do you see any script errors on the page?

      • Chitrank Dixit

        thanks for Quick reply Arvind

        I get the following error in my developer console on chrome

        TypeError: undefined is not a function

        at Scope.$rootScope.hide

  • Rajeev Kumar

    Hi Arvind, firstly thank you for this awesome post. However, I need some help to understand few things:

    1. When I ran your code, I am able to see appUsers collection but not bucketlist collection. Is that expected? or Am I doing something wrong? This does not affect the app and I am able to run it.

    2. Is there a way to get the bucketList for all the users? for example if I register 1, 2, 3 users and log in as user A, I want to see all the bucketlist created by the other user. Can you please help me achieve this?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Rajeev. To answer your questions

      1. MongoDB collections are created only when you have some data to save

      2. Yes, you can modify your query like

      Thanks.

      • Rajeev Kumar

        Thank you for the response Arvind. I tried your solution in manageList.js

        Something like this:

        server.get(“/api/v1/bucketList/data/list”, function (req, res, next) {
        validateRequest.validate(req, res, db, function () {
        db.bucketLists.find(,function (err, list) {
        res.writeHead(200, {
        ‘Content-Type': ‘application/json; charset=utf-8′
        });
        res.end(JSON.stringify(list));
        });
        });
        return next();
        });

        But this is still not retrieving all the users bucketList.
        Also in the client service.js file we have

        getAll: function (email) {
        return $http.get(base+’/api/v1/bucketList/data/list’, {
        method: ‘GET’,
        params: {
        token: email
        }
        });
        }
        This takes an email as a token. I saw the BucketList API and in that page it is mentioned that List API required a token.

        Can you please help me with some code example that shows , when the user logs into the app, he should be able to see the bucket list of his and other users as well.?

  • Turni

    Hi, what a nice tutorial !! Ii’ve learn a lot but i can’t work it, i’ve got a problem with the REST server. When i try to go to http://localhost:9804/api/v1/bucketList/auth/register I got a :

    {“code”:”MethodNotAllowedError”,”message”:”GET is not allowed”}

    it should not be handled by this part ? : (from server.js)

    // CORS
    server.use(function(req, res, next) {
    res.header(‘Access-Control-Allow-Origin’, “*”);
    res.header(‘Access-Control-Allow-Methods’, ‘GET,PUT,POST,DELETE’);
    res.header(‘Access-Control-Allow-Headers’, ‘Origin, X-Requested-With, Content-Type, Accept, Content-Type’);
    next();
    });

    I’ve tried res.header(‘Access-Control-Allow-Methods’, ‘*’); but no change .

    Thx again for this auto and keep doing this :)

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello Turni, Thanks!

      You need to make a HTTP POST request from postman or any rest client like curl. When you open the link in the browser, it becomes a GET request. Hence the error “GET is not allowed”

  • Alejanmat

    Great tutorial man!!

  • CdyP

    Great tutorial, thank you.

  • subbu

    Awesome post, great help

  • JoeDoh

    Hi Arvind, great tutorial.I am bit stuck of the manageList api though. Mainly with the DELETE. After entering the token value as user’s email and the id value of the items ObjectId as such, 54b6085e52c19ca836821eaa, I am getting the following error in POSTMAN:
    {
    “code”: “InternalError”,
    “message”: “Argument passed in must be a single String of 12 bytes or a string of 24 hex characters”
    }

    I have tried everything but nothing seems to perform the DELETE operation on the document. Any help is much appreciated!

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hey JoeDoh,

      Thanks! This seems to be an error from MongoDB end. (Take a look at : http://stackoverflow.com/a/26453755/1015046 )

      In the server side delete code,

      Check if req.params.id is the list ID (54b6085e52c19ca836821eaa).

      Thanks.

  • Amod Shankar

    Awesome tutorial. Thanks.

    I am facing a problem though in login API. Please find the screenshot for the same. It says :

    {
    “code”: “InternalError”,
    “message”: “Cannot call method ‘trim’ of undefined”
    }

    It seems the email and password fields are remaining undefined in the login API.

    The DB query gives the result after registering:

    > db.appUsers.find()

    { “_id” : ObjectId(“542b9e8841dadef56d770ccb”), “password” : null }

    Any help would be highly appreciated.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Amod. I did not find any screenshot in the comment. Can you re-post it?

      Looking at the info, looks like some issue during registration process. Are you sure the sent the data is received on the server?

      Thanks.

      • Guest

        Please find the screenshot.

      • Amod Shankar

        Hi Arvind,

        Somehow the image is not attaching in the reply.

        While registering, i did get the JSON response in postman having the _id and password=””.

        The DB query returns the following:

        { “_id” : ObjectId(“542b9e8841dadef56d770ccb”), “password” : null }

        I am not sure whether the data is coming to server or not(I am a newbie to node, and don’t know proper debugging :( ). Can you please suggest some workaround about how to check this ?

        Also, I am checking the API in POSTMAN. For registering and login, I provided the data in x-www-form-urlencoded field. If I give the data in the form field, it throws error. Shall I put the data in raw field as a JSON ?

        Thanks

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Hello Amod, NP.

          Sure. You can use console.log() to log the values to the Node console (the terminal/prompt where you started the node app). Pls. update the register method as below

          And in your node console, when the request is fired, you can see what is going on. Also do see if there are any other errors logged.

          Thanks,

          • Amod Shankar

            Hi Arvind,

            Following is the console log for /auth/register:

            user >> {}
            user.email >> undefined
            n undefined

            Now it is clear that data is not coming to server somehow.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            And also make sure you have included

            in server.js. Without which the request parsing will not happen.

            Thanks.

          • Amod Shankar

            Bingo ! got it to work.

            The required data was to be passed as a JSON object from ‘raw’ field of POSTMAN. The ‘x-www-form-urlencoded’ field doesn’t work here.

            I am getting another issue here –
            If the login credentials are correct, the API works like a charm, but if I pass a wrong email then the following response throws :
            {
            “code”: “InternalError”,
            “message”: “Cannot read property ‘password’ of null”
            }

            Here in manageUser.js, the method –
            pwdMgr.comparePassword(user.password, dbUser.password, function (err, isPasswordMatch)

            – is getting the dbUser field as null(since db.appUser.find returns null).

            Any pointers on this, please ?

            And thanks for your prompt responses :)

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Great!!

            You can find the solution from the last comment of ImINaBAR.

            Thanks.

          • Amod Shankar

            Thanks once again, got it to work :) You are the best :)

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Thanks!

          • Amod Shankar

            Hi Arvind,

            Small issue: after completing the deployment on heroku and mongolab, I tried checking the APIs from the application using chrome. It gives me 503 error as give :

            Request URL: http://mybucketlistapp.herokuapp.com/api/v1/bucketList/auth/register
            Request Method: POST
            Status Code: 503 Service Unavailable

            I ran the following also : heroku ps:scale web=1.

            Here are some recent logs of heroku :

            2014-10-08T10:27:33.768810+00:00 heroku[api]: Scale to web=1 by [email protected]
            2014-10-08T10:27:53.586043+00:00 app[web.1]: user.email >> [email protected]
            2014-10-08T10:27:53.586030+00:00 app[web.1]: user >> { email: ‘[email protected]’, password: ‘orange’, name: ‘amod’ }
            2014-10-08T10:27:53.670091+00:00 app[web.1]: n $2a$10$iWfu5NcZrHRIrM7WhVfUUOwRnNy4FjfJG0vgETMs.Dz9XK.FgGJDC
            2014-10-08T10:28:23.587710+00:00 heroku[router]: at=error code=H12 desc=”Request timeout” method=POST path=”/api/v1/bucketList/auth/register” host=mybucketlistapp.herokuapp.com request_id=1fe9369e-4021-4d47-8f5a-f2e69aef30ca fwd=”192.168.1.137,115.254.51.11″ dyno=web.1 connect=2ms service=30276ms status=503 bytes=0
            2014-10-08T10:28:23.589115+00:00 app[web.1]: POST /api/v1/bucketList/auth/register – – ms – –
            2014-10-08T10:31:16.451083+00:00 heroku[router]: at=info method=GET path=”/” host=mybucketlistapp.herokuapp.com request_id=00ece350-f0ae-49fc-9920-fc60f50b06ca fwd=”192.168.1.137,115.254.51.11″ dyno=web.1 connect=1ms service=2ms status=404 bytes=190

            Any pointers ?
            Thanks,
            Amod

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hi Amod, Couple of observations

            1. There are 2 script errors on the page (console tab)
            2. Are you running the page with a file:/// protocol? If you are making an Ajax call, you need to host the app.

            And if I navigate to http://mybucketlistapp.herokuapp.com , I get appropriate page as / is not defined. And looking at the error, looks like it is an app error. Is the local instance working fine?

            Also can you pls. verify if you have followed all the steps listed here : http://thejackalofjavascript.com/deploying-node-application

            Thanks.

          • Amod Shankar

            Hi Arvind,

            About your observations:

            1. First error is about cordova.js, and second is this 503 error.
            2. My bad, but same error persists even if I run from localhost:8100

            Yes, http://mybucketlistapp.herokuapp.com gives that error, I have no idea why. I followed all the instructions on that link. On local, everything works.

            I saw your git repo of the complete code, the url you provided : http://bucketlistapplication.herokuapp.com/ -also gives the / not defined error.

            I will deploy this on device and check once.
            Please make some guesses :)

            Thanks,
            Amod

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            BTW / not defined error is as expected.

          • Amod Shankar

            Hi Arvind ,

            Sorry to trouble you again.

            I have put logs inside the server in manageUser.js and can see the log printing upto

            console.log(“n”, hash);

            then at the function – db.appUsers.insert() , heroku throws a h12 timedout/503 error. By this it is clear that the APIs are accessible.

            It seems the connection to the mongolab is being timedout. I tried the mongolab url from shell using the username and password, it logs me in.

            Is there any way by which we can host a mongo database on heroku itself ? Also, any pointers on tackling with the nodejs timeout issue ?

            Thanks,
            Amod.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hi Amod,

            You can use MongoHQ https://addons.heroku.com/mongohq and you can use the MongoLab URL from your locally hosted app and check if it is saving in the DB as a confirmation.

            Thanks.

          • Amod Shankar

            Hello Arvind,

            Finally the end of eternity is here. Everything working.

            I am an idiot. After updating the mongolab url into the server.js file,I was simply doing an “git push heroku master”, without committing it to git first. In order to see if the database url was updated into server.js or not, I cloned the heroku server code into a new folder and that showed that I was using the old url itself :)

            In this process, I added mongohq into my heroku account and in order to make it work, lost some 30 rupees from my card(bigger idiocity 😛 ). Now things work using mongolab only :)

            Once again, I take this opportunity to thank you a million times for taking time for quick responses. You are a life saver :)

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Great! Glad I could be of help! Thanks.

          • http://pulpoficcion.tumblr.com/ J.Balczar

            Hi! I had the same problem, but i did what you did and the app works pefect on my localhost but in heroku doesn’t any idea? Thanks!

          • alexfs

            Hi, very new to ionic and mongoDB, can you please send me a full project for test, please?

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hello alexfs, the source code link is provided at the top of the post. Nevertheless, here it is : https://github.com/arvindr21/BucketListApp

          • alexfs

            thank you very much Arvind!

  • Somebody

    You are incredible. Thanks.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks.

  • Anson

    Hi Arvind, when I use a blank parameters to test the login api (/api/v1/bucketList/auth/login), there will be an error 500. And the error message is “Cannot call method ‘trim’ of undefined”. I guess that on the server/aut/manageUser.js file line 41-42, the user variable is undefined, not a string, which can use the trim() method. Is it that right, hope your reply

  • Denis C de Azevedo

    What a wonderful tutorial! Thank you for writing! So detailed and easy to follow.

    I was wondering how an hybrid app like this one (with AngularJS and PhoneGap) could work offline.
    Imagine there is no internet connection during a few hours. What is necessary to keep using the app (saving/editing items) and synchronize later, right after re-establish the connection?

    Thank you

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks @deniscdeazevedo:disqus!

      If you are looking for saving data offline, I would suggest using the Firebase version of this app. Firebase has the power to persist the changes locally and sync with the server when the network is back on.

      Thanks!

  • George
    • George

      Just ignore this issue, looks like the older version of ionic, has problems with $rootScope. Update ionic seems to have solved the problem. Thanks

      • http://thejackalofjavascript.com/ Arvind Ravulavaru

        Great! Thanks!

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello @disqus_Hpt7By9gji:disqus, Thanks!

      Looks like app.js is not included before services.js, hence the error

      hide() is defined in app.js

  • vamshisuram

    thanks a lot for the nice tutorial.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks @vamshisuram:disqus

  • gerbie

    Hi Arvind, Thanks for this awesome tutorial. I followed all the steps but somehow I cannot connect to my mongolab instance. The error that I get on heroku is

    /app/auth/manageUser.js:5
    db.appUsers.ensureIndex({
    at Module.load (module.js:356:32)

    thoughts?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks Gerbie. Can you try the same removing

      db.appUsers.ensureIndex({
      email: 1
      }, {
      unique: true
      });

      from managerUser.js.

      • gerbie

        Hi Arvind! Thanks for responding :) I did just that but now it’s complaining about

        “Cannot call method ‘insert’ of undefined”

        I don’t think it’s able to connect to the mongolab instance. I used your code that you have on github.

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Couple of ideas,

          1. if you have mongodb installed on your local machine, you can try accessing the MongoLab environment using the mongo shell. Open a new terminal and run the below command

          >> mongodb://admin:[email protected]:27367/bucketlistapp

          Update the above details with your connection string. Or you can use the above connection string as is.

          If you are able to tunnel through using your local machine, MongoLab is working fine. You can use the standard MongoDB queries to check what is present inside your DB collection.

          2. Can you pls recheck https://github.com/arvindr21/BucketListApp/blob/master/prod/server/server.js with the connection string and path?

          Last resort, can you share your code, I can try running it?

          Thanks.

          • gerbie

            Arvind, I’m stuck :(

            Here’s my code:

            https://github.com/reggarcia/bucketlistapp

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hey Gerbie, Found the issue. My bad!

            When instantiating the collection, I have used ‘users’ collection in server.js

            var db = mongojs(‘mongodb://admin:[email protected]:27367/bucketlistapp’, [‘users’,’bucketLists’]);

            and in manageUser.js have used ‘appUser’ as reference.

            db.appUsers.ensureIndex({
            email: 1
            }, {
            unique: true
            });

            The above is changed to

            db.users.ensureIndex({
            email: 1
            }, {
            unique: true
            });

            and things look good.

            Thanks for pointing it out.

          • gerbie

            Thank you! I’m so excited to build more functionality into this app! Kudos!

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Thanks!

          • Alexfs

            Hi Arvind, very good tutorial, can you please send me the full project? Thank you

          • gerbie

            I was able to fix the issue:

            Changed this line:

            var db = mongojs(‘mongodb://admin:[email protected]:37617/bucketlistapp’, [‘users’,’bucketLists’]);

            to
            var db = mongojs(‘mongodb://admin:[email protected]:37617/bucketlistapp’, [‘appUsers’,’bucketLists’]);

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Yup! That was the solution I mentioned below.

  • gerbie

    Hi Arvind, great tutorial.I tried to run http://localhost:9804/api/v1/bucketList/api/auth/register on Postman but it gives me this error:

    {

    “code”: “ResourceNotFound”,

    “message”: “/api/v1/bucketList/api/auth/register does not exist”

    }

    What does this mean?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello there, Thanks!
      This means that the RESTify app hosted on 9804 is not having a route with path “/api/v1/bucketList/api/auth/register”

      • http://guizishanren.com/ Herbert Yang

        Hi Arvind, thanks for this great tutorial! I ran into the same issue and saw the same error message that said the “code”: “ResourceNotFound”,
        “message”: “/api/v1/bucketList/api/auth/register does not exist”. How to fix this issue?

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Hello Herbert. Thanks!

          I quickly re-ran the tutorial and things seems to be working fine. I have used the same versions of the node packages as shown in the package.json above. I have also installed the latest versions of these package and the app seems to work fine.

          Can you host the code somewhere and give me a links? I can take a look.

          Thanks.

          • http://guizishanren.com/ Herbert Yang

            Thanks for the reply Arvind.

            I literally copied and pasted your exact codes from the server part. Here’s my package.json:

            {
            “name”: “wuhan”,
            “version”: “0.0.0”,
            “description”: “server for Linkqlo app”,
            “main”: “index.js”,
            “scripts”: {
            “test”: “echo “Error: no test specified” && exit 1″
            },
            “author”: “Herbert Yang”,
            “license”: “ISC”,
            “dependencies”: {
            “morgan”: “^1.1.1″,
            “bcrypt”: “^0.7.8″,
            “restify”: “^2.8.1″,
            “mongojs”: “^0.13.0″
            }

            }

            After I entered” node server.js” in the command-line, shell prompt said “Server started @ 9804″. In my Chrome browser, I tried “http://localhost:9804/api/v1/bucketList/auth/register” url and got “{“code”:”MethodNotAllowedError”,”message”:”GET is not allowed”} ” message. When I tried”http://localhost:9804/”, I got “{“code”:”ResourceNotFound”,”message”:”/ does not exist”}” .

            What am I doing wrong you think?

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hello Herbert.

            /auth/register endpoint is of type POST. You cannot fire it using the browser. The browser will change http://localhost:9804/api/v1/bucketList/auth/register to GET. and hence you see the error

            Please use postman or curl or any other REST client to access that end point.

            And since we did not define any action on '/' or `http://localhost:9804/' end point with type GET, you see this error

            Thanks.

          • http://guizishanren.com/ Herbert Yang

            Got it. Thank you Arvind!

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Thanks.

  • weinan

    Hi Arvind, thanks for the tutorial. Manage to deploy it onto openshift for testing. I have lost touch with programming for over 3-4 years. Your tutorial provide an easy to follow learning. I hope based on your tutorial I can develop something more complex. By the way, you mentioned that if this app were to go production, we need to change the user authentication method, i’m not really understand about this. could you tell me where can i learn user authentication for production app?

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks weinan! Good to know that. If you are done with this tutorial, you can checkout building Hybrids with Firebase as backed (link at the top of this article).

      Coming to User authentication, When a request comes to our server, we need to check if that is legit request from our “own” client. For that, in the above app, we are using the email id as a “authentication token”. If the token is a valid email address and if that email address is present in our DB we assume that the request is from a legit client.

      The security threat is that, any user can sniff the URL we are sending the data to and the format. If the “hacker” starts a hit and trial with a few email address and was successful to get the data of any user, the app is no more secure. This is fine for a test app.

      In your production app, I would suggest using OAuth 2.0.

      The concept is pretty simple. When a client make first contact with a server, It needs to “register” with the server for that session (with an API key registered to that client, which is known only to the clients of our App). So on first contact, the server tracks the client, stores its details and generates a token with a validity (1 hour or 1 day or 1 year). This token is stored in DB or a file, which will be used to validate the authenticity of the client later. Once the client receives the token, it can start making actual API calls with token as in the cookie or a request header, depending on how the Server API understands requests.

      Once the server receives a request, it will first check if the token from the request is valid & not expired and then serve the request. If the token is invalid/expired, the server will return a 403 – Forbidden. To make your app more secure, keep the token expiration for a short duration like a minute. So after a minute if the client needs to make a new API call, it needs to first get the token and then only it can fetch the actual data.

      This is the same implementation that goes with standard API services like Twitter API, Google API, GitHub API etc. You can read more here: http://en.wikipedia.org/wiki/OAuth

      Do let me know if you need any more clarification.

      Thanks.

      • weinan

        Hi Arvind, I took a look on firebase article you wrote. I registered a firebase account, downloaded your code onto my pc, modify the firebase url and build a android app out of it. Beside the sign in function, all other feature just work with a single step of updating firebase url. I checked my firebase data, all the data appear in the database.
        One thing that seems odd is the sign in function is not working on native but working when i do “ionic serve”
        May I check, with the firebase, the validation you provided is good enough for production? or still have to do OAuth 2.0?

  • Mark Chiles

    Very cool. I did some updates and split out the server versus client to showcase the differences for myself and others, using AWS and MongoLabs. But a very informative tutorial.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Cool. Thanks!

      • Mark Chiles

        Arvind, I was wondering if you’ve broken it out further to have an edit controller? I’ve figured out the approach for the API to do an update to an “item” per “_id”, but having a tough time getting the edit contoller there. What I was working on was having an “edit” button, which opens a box, similar to “new” so that you can see the “item” in the box and update it. Any ideas? Thanks!

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Mark Chiles I have not tried the below solution, but this should work.

          Server
          ——–
          On the server, as you have mentioned, you can use the put controller (https://github.com/arvindr21/BucketListApp/blob/master/dev/server/list/manageList.js#L46) as is and post the data to this end point. The put code is written in such a way that, the value of the existing record will be the overwritten by the values from the request params. This takes care of the server.

          Client
          ——-
          Coming to client, first thing you need to do is create a template similar to the ‘newitem.html’ (https://github.com/arvindr21/BucketListApp/blob/master/dev/client/bucketListApp/www/templates/newItem.html). This will hold the form where you will show the item in edit mode.

          You can show just the name of the item or you can show both the name of the item as well as isCompleted property, up to you. Once this is done, you will point the template to our edit controller (ng-controller=”editCtrl”).

          Next, we will update our edit template with a new icon or button like and you would pass the id and item text to the edit item method.

          Next, In the ‘myListCtrl’, you will add code (https://github.com/arvindr21/BucketListApp/blob/master/dev/client/bucketListApp/www/js/controllers.js#L95) to load the template. But here inside the editItem method, we will dump the current item’s id and text and then show the popup

          $scope.editItem = function (id, text) {
          $scope.data = {
          id : id,
          text : text
          }
          $scope.editTemplate.show();
          };

          And since our edit template is already mapped to the data.item model, using ng-model=”data.item”, the value will automatically show up (2 way databinding).

          Finally in our editCtrl, (similar to newCtrl https://github.com/arvindr21/BucketListApp/blob/master/dev/client/bucketListApp/www/js/controllers.js#L187) you can fire the put request using the existing put service (https://github.com/arvindr21/BucketListApp/blob/master/dev/client/bucketListApp/www/js/controllers.js#L111).

          Hope this helps.

          • Mark Chiles

            Thanks, Arvind. I’ve got everything there, but the trouble I’m having, for whatever reason, is getting the item._id and item.item to show up on the edit page. The controller is there and working, yet the “id” is undefined, obviously since it’s not showing up. Any further thoughts? Thanks!

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Can you try putting breakpoint or alert inside the $scope.editItem = function (id, text) {} ?
            Just to check if the values are coming till here.

          • Mark Chiles

            Yes, they are showing up with an alert script.

            $scope.alert = function(){

            alert(‘Hi ‘ + $scope.data.id);

            }
            $scope.alert();

            Does give me the correct ObjectId in the popup alert.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Cool Thats half the battle won! Next, can you confirm if your input tag is

            — having the ng-model value as data.item and not just item.
            And also, you have the

            ng-controller=”editCtrl”

            directive added to the template.

          • Mark Chiles

            Yep, those are it.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Hmm.. Strange. Is there a chance I can see the code? Probably a Github link?

          • Mark Chiles

            Sure. I’m sure it most likely has to do with my controllers.js file. https://github.com/mechiles/bucketListClientDev

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            @markchiles:disqus You can find the updated code here : https://github.com/arvindr21/bucketListClientDev
            The caveat here is this
            https://github.com/arvindr21/bucketListClientDev/blob/master/js/controllers.js#L100

            $ionicModal.fromTemplateUrl(‘templates/editItem.html’, function(modal) {
            $scope.editTemplate = modal;
            }, {
            scope: $scope,
            focusFirstInput: true
            });

            This will inject the scope to the popup. Now all the modal bindings will work as expected.
            Note: The code has some issue with closing the popup.

          • Mark Chiles

            Thanks. I was on the right track. Got all of the elements working now, including the closing modal windows and some css clean up.

          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Awesome. Thanks!

          • Mark Chiles
          • http://thejackalofjavascript.com/ Arvind Ravulavaru

            Thanks @markchiles:disqus Forked it for future reference.

  • ImINaBAR

    Done! Awesome, I’ve learnt lot, hand typed everythig, so I had a lot of bugs to bust, which means more learning.
    Thanks a lot.
    One last thing though:
    on the server/aut/manageUser.js file, if you try to log in through server.post('/api/v1/bucketList/auth/login' with a non existent email.

    db.appUsers.findOne({
    email: req.params.email
    }, function (err, dbUser) {
    console.log(err,dbUser);//outputs: null,null (which is supposed to happen)

    //here be errors
    });

    that will provoque an undefined error in the following line, and a subsequent error 500 in the server. What I did to prevent that is the following.

    db.appUsers.findOne({
    email: req.params.email
    }, function (err, dbUser) {
    if(!dbUser){//if the database finds no email, it will return null, but any falsey will also mean something's amiss
    res.writeHead(403, contentTypeTipo);
    res.end(JSON.stringify({
    error: 'Invalid credentials. User not found.'
    }));
    }

    //hre were errors
    });

    then again, I’m new at this.
    I won’t bug you anymore… in this article at least. I see you are frequently posting really good articles.
    Now I’ll build what I wanted to build from the start, which I was about to do in Sencha Touch, but figured that I should learn some Angularjs.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Great! Thanks for the code to handle non existent email.
      And all the best on your Quest. May the force be with you! :)

  • ImINaBAR

    Noted something:
    The code on the services.js file, on line: 67
    the path shown is:
    '/api/v1/bucketList/data/list/'+id
    Shouldn’t it be '/api/v1/bucketList/data/item/'+id ?
    I’m inching my way through this, because I’m typing by hand and reading the docs on almost every method I encounter.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Nice catch! I don’t know how I missed it!
      Fixed it now.

  • ImINaBAR

    Maybe I’m the only one with a windows machine, but I couldn’t npm install bcrypt on win 7, tried building it locally (as sugested here: http://stackoverflow.com/questions/10153317/cannot-install-bcrypt-node-js-module-on-centos-server/10568427#10568427), but I’m missing Python and am not in the mood of installing yet another something, so I’m trying with bcrypt-nodejs which should work similarly, I’ll post here how it goes.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Cool.. Any luck with bcrypt-nodejs?

      • ImINaBAR

        Not ideal but I got it working synchronously.
        .genSalt() and .hash() methods failed giving an error 500 in the server and no further error message.
        But using .genSaltSync() and .hashSync() worked fine, so the cryptoPassword method looks like this:

        module.exports.cryptPassword = function (password, callback) {
        return callback(null, bcrypt.hashSync(password, bcrypt.genSaltSync()));
        };

        Still working through this great tutorial, I’m learning a lot (never coded for node before).

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Cool. Thanks for sharing. Glad that you are having fun. Let me see if I simplify the auth for windows.

  • iplaksiy

    Hi Arvind, thank you for putting this tutorial together. It was very detailed and very easy to follow along. I was wondering if you could create a Part 2 and continue the steps needed to actually deploy the application past the local environment and into an emulator and/or device. You included a paragraph on the steps to do so, including some links, but it has proven rather difficult to switch from your detailed teaching method to the other sources you have included (e.g. Heroku walkthrough), if not frustrating.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello iplaksiy, Thanks much!!.

      For the server deployment, I have written an article (upon your request :)) as how to deploy a Node application to Heroku (http://thejackalofjavascript.com/deploying-node-application/) you can refer that to host your application.

      For the Ionic App, please follow this (http://thejackalofjavascript.com/phonegap-quick-start/) to deploy the app on PhoneGap Build. Once that is done, you can download device installers.

      If you are still facing issues, do let me know.

      Thanks,
      Arvind.

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Hello iplaksiy, Thanks much!!.

      For the server deployment, I have written an article (upon your request :)) as how to deploy a Node application to Heroku : http://thejackalofjavascript.com/deploying-node-application you can refer that to host your application.

      For the Ionic App, please follow this post : http://thejackalofjavascript.com/phonegap-quick-start to deploy the app on PhoneGap Build. Once that is done, you can download device installers.

      If you are still facing issues, do let me know.

      Thanks,
      Arvind.

      • iplaksiy

        Wow! That was fast and is exactly what I had in mind!

        Thanks again and much appreciated!

        • http://thejackalofjavascript.com/ Arvind Ravulavaru

          Thanks!

  • spex86

    Awesome tutorial! I broke this out into a few days so I could research more on each section as I went along, but this is a serious intro to end-to-end hybrid app development. Well done and thanks for writing it all up!

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Thanks spex86. Glad I could be of help!

  • http://thejackalofjavascript.com/ Arvind Ravulavaru

    Awesome Ron! And Thanks for the kind words. Really happy that this post was helpful.

  • http://www.realtidings.com/ Ron Northcutt

    Wow – fantastic tutorial! I used this as a guide to help me build a basic Todo app in about 5 hours for my DOPE project at work. I’ve got experience with sysadmin, so I created my own server with Digital ocean, but otherwise I had no experience with Node, MongoDb, Ionic, or Angular JS. I’m mostly a PHP dev.

    Still, this made it very easy for me to create my own app, and the experience has excited me about another project I want to begin. Thank you so much for putting this together!

    • http://thejackalofjavascript.com/ Arvind Ravulavaru

      Awesome Ron! And Thanks for those kind words. Really happy that this post was helpful.

    • ImINaBAR

      Wow, Ron, your comment has inspired me to follow your steps, I come from a PHP background also. I’ll let you know how it goes.

    • Jose Faro

      Awesome and awesome, I am coming frm php too.