Create A Real Time Chat Application With The CEAN Stack and Socket.io

I’ve always wondered what it took to develop a real-time chat application.  Being able to broadcast messages instantly to other people using the same application is a pretty cool concept.  Since I’ve been playing around a lot with the Couchbase, Express, Angular, and Node.js (CEAN) stack, I figured it would be pretty awesome to try to make a chat application using those technologies.  To make life easy, I found a pretty sweet library called Socket.io, which will do a lot of the tough broadcasting work.

We’re going to see how to create a very simple chat application, that with a little imagination, can become something incredible.

Before getting too deep into this, let’s break down our technologies and the part they’ll play within this application.

We’ll be using the CEAN stack, sometimes referred to as the CANE stack, for this particular application.  Node.js will power our server and accept communications and broadcast communications to and from the client application.  The Node.js server will make use of the Socket.io middleware and Express framework.  Our client front end will be powered by AngularJS, HTML, CSS, and the client side Socket.io library.  To spice things up, we’re going to be using Angular 2 which is currently cutting edge.

You might be wondering, well where does Couchbase fit into this?  We are going to store our chat messages in Couchbase Server so people who join into the chatroom late, won’t miss out on previous conversations.  You can use your imagination and do something with Big Data to analyze the chat data if you really wanted to.

To keep things organized, we’re going to tackle this project in the following parts:

  • The Node.js backend
  • The Angular 2 front-end
  • Couchbase integration

This should make things easier to follow.

The Node.js Backend

I’m going to assume you’ve already installed Node.js on your computer and the Node Package Manager (NPM) is fully functional.  Our entire project will exist on our Desktop, so create a directory there if you haven’t already.  From your Command Prompt (Windows) or Terminal (Mac and Linux), execute the following:

The above command will create a package.json file that looks similar to the following:

Feel free to edit it as necessary.

Inside your project directory, create a modelspublic, and routes directory.  The models directory will contain all the Couchbase database logic and the routes directory will contain all your RESTful API endpoints.  The public directory will contain all your front-end application code, which in reality doesn’t have to exist within your project.

At the root of your project you should also create an app.js and config.json file.  The app.js file will contain the core Node.js server logic and the config.json file will contain connection information for Couchbase Server.

Before we open any of these files and start coding we should probably download any project dependencies.  From the Terminal or Command Prompt, execute the following to grab all the Node.js middleware:

It is safe to start designing our app.js file.  Open it and add the following code:

We need to understand what is happening here.

First we are including the middleware that we downloaded into our project.  Then we are starting the Socket.io and telling it to listen for data.

The above two lines declare the public directory as part of our project as well as alias the node_modules directory to be accessed as scripts via the front-end.  We need some of the Angular 2 libraries from node_modules which is why this is necessary.  It may not be best to expose all your node_modules information here, but it works for the purpose of this example.

After we set up these public directories we need to define where our API routes will exist.  To be honest we only have one route, but it needs a place to live.  With that defined, we can move onto the heavy lifting of Socket.io:

When a connection is established to the server it will listen for broadcasts from that particular open socket.  The broadcast in this scenario is a developer defined chat_message broadcast.  When received, the server will send it to all other sockets that are connected, including the one who sent it.

Finally, we start listening on port 3000 for activity.

Now we can jump into defining our route.  Inside your project’s routes directory, create a file called routes.js and add the following code:

There isn’t anything exiting in the above.  Not until we hook up Couchbase.  However, this is just a route we’ll use for fetching all NoSQL documents that exist in the database.  This will catch up other chatroom users with the conversation.

Congratulations, the Node.js setup is done!  We just need to get Couchbase integrated and our front-end completed.

The Angular 2 Front-End

This might be a little exotic to you if you’ve never seen Angular 2 before.  In particular, we’ll be using TypeScript with Angular 2, which means we’ll need to define a tsconfig.json file.  Before we do that though, we need to include the rest of our dependencies.  At the root of your project using the Command Prompt or Terminal, execute the following:

Feel free to use a different version of Angular 2 if the 2.0.0-beta.0 has become out of date.

Create public/tsconfig.json and add the following to it:

Now our IDE should recognize and compile TypeScript for us.

Next we need to create an index.html file that will contain all our script and style includes.  This file will sit next to the tsconfig.json file.  In your project’s public directory, create index.html and add the following code:

A few things to note here.  I did not create the styles, but instead took them from the Socket.io documentation.  That is pretty much where my documentation looting ends.

Notice all the script includes referencing the scripts directory?  That is the alias we created in the Node.js section.  The System commands are pointing to the app directory that we haven’t created yet.  This is where the meat of our application will reside.

Don’t forget to download the Socket.io client JavaScript library.  It should be placed in your project’s public/js directory.

Time to go one level deeper.  Create public/app/app.ts and include the following:

This is the base of our Angular 2 logic.  We’re essentially just defining a page router so that we can isolate our logic in specific pages.  Our project will only have a DefaultPage, but you can easily expand upon it to add more pages.  More information on Angular 2 page navigation can be found in a previous post that I wrote.

The public/app/app.ts file pairs with public/app/app.html which should contain the following code:

More theming can be done here if desired, but for this project, our core theming is in the page itself, not the parent pages.

Our single page will be found in the public/app/default directory.  The file pair that exists in that directory will be default.ts and default.html.

Let’s start by cracking open the public/app/default/default.ts file and adding the following code:

To break this file down, we’re including the Angular 2 Component and View dependencies as well as the dependency required for making HTTP requests.  Remember, our application will at some point in time, make HTTP requests to get data from our database.

Notice the declare var io: any; line.  TypeScript won’t naturally understand the functions and classes in the Socket.io JavaScript library so we must first declare it.

Inside our DefaultPage class we define our variables.

The constructor will be executed as soon as the page launches. We are initializing our messages array and making an HTTP request against Node.js for any data that might exist in the database.  Up until now we are just returning a constant {message: "woot"}, but that will change real soon.  We are also firing up the Socket.io client library and pushing any received messages to the messages array.

The send(message) function will send messages to the Node.js server and clear the input box on the front end.

Now let’s jump into the public/app/default/default.html file and add the following few lines of code:

In this UI file we’re looping through the messages array and displaying each message in a list.  The input box is mapped to our chatBox string and it is passed in when we perform a button press.

To use the front-end you’ll need to compile the TypeScript files.  Some editors like Atom do this for you, but if you don’t have JavaScript files automatically being generated, run tsc from the Terminal with the directory that contains tsconfig.json as the current working directory.

Congratulations, your front-end with Angular 2 and TypeScript is now complete!  Now we just need to get our database layer included.

Couchbase Integration

Let’s get Couchbase into our project for storing chat messages.  If you’re unfamiliar, Couchbase is a NoSQL document database that is open source.  It is incredibly easy to install and configure on your machine.  Head over to the official Couchbase downloads page and get the latest version.

Once installed, create a new Couchbase bucket called web-chat or whatever you prefer.  We’ll be using N1QL, which is SQL-like queries, against our data.  To use N1QL we need to have at least one index created on our database bucket.  This can be done through the Couchbase Query (CBQ) client installed with Couchbase.

To run CBQ on a Mac, execute the following from the Terminal:

If you’re on Windows, run CBQ in the Command Prompt by executing the following:

With CBQ up and running we need to create our index.  Execute the following:

Wew, Couchbase is now ready to go.

We need to define our server and bucket information in the config.json file we created at the beginning of the tutorial.  Open your project’s config.json file and add the following:

Remember to change things where appropriate.

We never included the Couchbase Node.js SDK, so do that by executing the following at the root of your project:

Head back into your project’s app.js file as we need to make some edits:

Take note of the highlighted lines as that is what we changed in particular.

We’re including the Couchbase middleware and the configuration file that we have at the root of our project.  We are opening a connection to the server as well as the particular bucket.  We included a ChatModel that is foreign to us at the moment, but won’t be soon.  The ChatModel is where all our database logic will exist.

Finally, inside the Socket.io listener block, we are calling the ChatModel.create method every time a new message is received.  This method will save the messages to the database and then broadcast them to the clients.

Let’s take a look at that ChatModel class.  Open your project’s models/chatmodel.js file and include the following code:

We have two functions in this class.  The create function will take the chat message, create a unique id, and then store it into Couchbase.  The getAll function will run a N1QL query to get all documents from the bucket.  Both functions are very basic and can be expanded upon with a little imagination.

What actually calls the getAll function though?  This is where our /fetch route comes into play.  Head back into your project’s routes/routes.js file and change it to look like the following:

We are done!  Our chat application now works with a database.

To run this project, type node app.js from your Terminal or Command Prompt at the root of the project.

Conclusion

We just made a pretty massive full stack application.  We made use of the now bleeding edge Angular 2 framework in addition to Couchbase, Node.js, Express Framework, and Socket.io.  With all of these technologies combined we were able to make a real time chat application that stores messages in a NoSQL database to be accessed at a later time.

The full source code to this tutorial can be found on GitHub.

Nic Raboy

Nic is a skilled application developer who has released several native and hybrid mobile applications to iTunes and Google Play. He writes about his development experiences related to making web and mobile app development easier to understand and has experience in Android, Node.js, Apache Cordova, Java, NoSQL, SQL, GoLang, NativeScript, and Unity3D.

  • goliatone

    Is this sponsored by Couchbase?

    • I work for Couchbase, but they did not ask me to write this post. Anything that goes on my blog is something I truly feel is helpful to people.

      Everything I listed in this article is either open source or free. If this post or future posts were sponsored by Couchbase or another company, would that be a bad thing?

      Best,

  • arham jain

    Hey Nic! This post contained a lot of different things. You covered three things that I will be using in my next project: Node.js, Socket.io, and Couchbase. My project is to write a MMO server for a game that I am currently developing. I had a question about Couchbase for that use case. What kind of latency would Couchbase offer? Say I stored everything in a Couchbase before sending it to the other clients. Would their be very noticeable lag, or would the read/write transactions be fast enough to go unnoticed by most human? In reality, I would probably broadcast first, then write the data, but I want to know whether Couchbase would be usable in a real time game format.

    Thanks,

    Arham J.

    • You shouldn’t have an issue with latency. Couchbase has a build in caching layer that makes use of RAM and data sent to it is asynchronously persisted to the disk. Now of course there are plenty of other factors that will drive this. For example, are you running a server with acceptable specs? How about the network pipes?

      I’d say go for it. If anything it will much quicker than using a plain old MySQL server.

      Follow up with me on this project. It sounds interesting 🙂

      • arham jain

        My server, for now, is going to be my Raspberry Pi. I know that a RPi would be very impractical for a database, but only two players will be connected at a time. My upload speed is 6mpbs up, which is more than enough for the small amount of json that is sent. Glad to see that you think it is interesting. I will probably use couchbase once more of the server is written.
        Development (Client) is happening at http://www.github.com/Ajusa/Spell

        Development (Server) is happening at http://www.github.com/Ajusa/Spell-Server

        Let me know if you have any feedback. The game is being worked on by myself and my friend. We are both in high school, so don’t expect too much 😀

        • Cool, just remember Couchbase Server won’t run on ARM so you’ll need to host it somewhere beyond the Raspberry Pi.

          • arham jain

            Ah, okay. I will add couchbase once people actually start playing the game. At that point, I will switch to DigitalOcean. DO works well with couchbase correct? There isn’t any huge lag or anything?

          • From a networking perspective Digital Ocean works fine. Like I mentioned before, you need to also worry about the specs you put into it.

  • Duncan Underwood

    Hi. Great blog and thank you. But im having issues when running the app. im getting a 404 error. where the console says its trying to look for app.js in the public/app folder. there is a app.ts file in there though

    • Duncan Underwood

      CLI versions

      • Duncan Underwood

        i dont see the scripts folder in your public folder on github. ?

    • You need to compile the typescript files to get the JavaScript equivalents. Run tsc in your terminal

      • Duncan Underwood

        Ok. Will give that a go. Did I miss that step in your instructions?

        • You’re right, I forgot to include that step. I’m so used to my editor doing it for me. I’ve updated the post at the end of the front-end section.

          Best,

          • Duncan Underwood

            Thanks Nic.

  • Michel Bottan

    Hi,

    Thanks for the tuto! I’ve forked it and created a Dockerized version of the app.

    https://github.com/abmxer/cean-web-chat

    Cheers!

    • Awesome! Thanks for sharing this 🙂

  • Franz Silva

    Hey Nic Cool Tutorial. Ive created a pull request on the repo to upgrade Angular 2 to Beta.7, and added something to the Chatmodel. Basically Sorting.

    • Awesome! Thanks for taking the time to contribute 🙂

  • This is pretty cool. Real time chat app is known and useful for todays generation. Everyone is using technology in making their lives easier. Just like this app, people or users can directly send messages to their loved ones. Thank you for sharing this one. It’s quite interesting.

  • Joel W

    Thanks for the Tutorial. I am just starting to learn Couchbase and I have a couple of questions. Is there a reason why you store the document ID in the json value in Couchbase? What is the reason you put chat:: in front of the key?

    • It is just how I’ve chosen to model my data. By including chat in the key I am using a compound key. Makes my documents more organized if I have more beyond just chat document types. I could have just called it 1 and stored chat as a type property instead.

      Model how you see fit 🙂

  • Dan

    Hi Nic, Great starter for those make beginner steps with CB and Angular2. With that, quick question…
    How would you handle a reference to couchbase module as well as config file if you would have moved the model into the app directory (cean-web-chat/public/app). I tried number of approaches and none of the references from the root directory of the solution are available via required() in public/app directory. Any ideas?

    • Post what you’ve tried on github and I’ll have a look

      • Dan

        Here is the github for my test https://github.com/dev4201/couchbase-angular2-test/tree/master/couchbase-angular2-test
        If you open app.component.ts you’ll notice require statement, which errors for any file that is not part of /app directory.

        • So you’re trying to reference a Node.js file from your Angular 2 file. Angular 2 is frontend while Node.js is backend so while they are the same language (JavaScript) they are two different technologies.

          This tutorial is possible because the Node.js backend is using the Socket.IO server and the frontend is using the Socket.IO client. The backend takes control of Couchbase, but the frontend should never do this.

          Best,

  • David Donaldson

    Im loving the tutorial but I’ve hit a brick wall. I cant create an index in couchbase. I keep getting an error code 5000 “connection refused”. I’ve tried creating the bucket again several time with and with out a password and modifying my query to suit but no luck.

    Any advice would be much appreciated as I would love to complete this tutorial 🙂

    • What version and edition of Couchbase? Also is it being hosted remotely out locally?

      • David Donaldson

        Version: 4.5.0-2601 Enterprise Edition (build-2601)

        Its just being hosted locally.

        • Strange!

          Since you’re using 4.5 EE, what happens when you try to create the primary index via the Query Workbench within the Couchbase dashboard?

  • Thomas Thai

    Nic, heads up on a little typo: “There isn’t anything exiting in the above.” I think you meant “exciting?”

  • Thomas Thai

    You got me hooked on your blogs! With regard to getting the socket.io client for Angular, you provided the “download” link to socket.io’s site which said:

    Getting the Socket.IO Client
    We distribute the browser client through our CDN, for free, forever.

    If you want to grab the source, grab the socket.io.js file from the socket.io-client repository.

    Our client codebase runs on both Node.JS and browsers, and it’s also compatible with browserify.

    Which led me to click on “socket.io-client repository” that took me to their GitHub. In the parent director there is this file:

    https://raw.githubusercontent.com/socketio/socket.io-client/master/socket.io.js

    Is this the socket.io client I should download to the js directory?

    • Yea it should be the correct file. However, this tutorial is slightly dated with the new Angular 2 release out. You would probably have to change a few things to get it to work. I’ll probably revisit this post soon.

      • Thomas Thai

        Thank you Nic.

  • Thomas Thai

    Nic, I got this working under PostgreSQL using the same Angular version as this tutorial. I can see messages exchanged back and forth when I tested it between my laptop browser and mobile phone browser. The only thing that is not showing up is the initial loading of old messages when someone first loads up the page. That was suppose to happen right? I put some debugs in the default.ts page to see if it’s loading old messages from the database and it is, just not displaying them.

    export class DefaultPage {

    // DEBUG
    console.log(“DefaultPage{}::constructor()”);

    // DEBUG
    console.log(“DefaultPage{}::constructor:data = “, data);

    // DEBUG
    console.log(“DefaultPage{}::constructor:this.messages = “, this.messages);

    Here is some output from the console from browser page refesh:

    message: ‘Mobile: I am portable. You suck.’,
    message_date: 2016-11-13T00:34:51.000Z },
    anonymous {
    message_id: ‘417e4d52-4590-42a3-a6a2-a91a2661dc5a’,
    message: ‘Laptop: :/ You hurt my feelings.’,
    message_date: 2016-11-13T00:35:13.000Z },
    anonymous {
    message_id: ‘482507ad-617c-4d81-9b79-eeae343cf931’,
    message: ‘What feelings? You’re a laptop!’,
    message_date: 2016-11-13T00:36:01.000Z },
    anonymous {
    message_id: ‘688be461-8f17-4d31-8df1-c5ba5b54b7f0’,
    message: ‘Laptop: Hello again’,
    message_date: 2016-11-13T01:25:12.000Z },
    anonymous {
    message_id: ‘3e5a94f0-655a-4961-a8e2-c8c1000b4398’,
    message: ‘Hi Laptop. Are you still hurt?’,
    message_date: 2016-11-13T01:26:44.000Z },
    anonymous {
    message_id: ‘85184c22-624d-417a-b4db-c41092f8d9c6’,
    message: ‘Yes still hurt from your mean comment. I don’t think you have feelings!’,
    message_date: 2016-11-13T01:30:39.000Z },

  • Thomas Thai

    It’s now working under Angular 2 beta 17 with ProgreSQL too. Next I will check out the Ionic 2 client. Thanks for the work.