WebSockets with Angular2 and RxJS

WebSocket is a technology that allows two way communication over single TCP socket. It is designed to be used between client’s browser and application server.

The support of the WebSocket is getting better and better, getting to the point where this technology can be widely used in the production environment. Below you can find compatibility table.

Source: caniuse.com

Angular2 framework is modern framework to create rich web apps. It is more slim and modern version of it’s predecessor, leaving much more flexibility in choosing different libraries. One of Angular2 companions is RxJS library. It is implementation of Observable pattern, with rich set of tools to help you with manipulation those streams of data.

WebSocket is perfect match for all the power that RxJS gives to you. It is asynchronous stream of messages that you need to react to. A thing that Rx is created for. I’ll show you how to make simple implementation of WebSocket service in Angular2.

First things first — we need to start with the basic imports. That would be Rx and Injectable annotation in our case.

import Rx from ‘rxjs/Rx’;
import {Injectable} from ‘angular2/core’;

After that we are free to create new service. This implementation will have some serious constraints to simplify things and keep our focus on most important stuff. We will be able to connect to only one WebSocket per service instance. That would be handy to share one connection between different Components. Thanks to hierarchical injector this could even work out in some simple scenarios. Let’s take a look at basic skeleton.

Injectable()
export class WebSocketService {
private socket: Rx.Subject<MessageEvent>;
  public connect(url): Rx.Subject<MessageEvent> {
if(!this.socket) {
this.socket = this.create(url);
}
    return this.socket;
}
}

We create Injectable service. This is Angular’s2 way for creating services. Beneath the annotation we create usual ES6 class. Thank’s to TypeScript we can also use type declarations. In this case we have one private property of type Rx.Subject<MessageEvent>. This would be our socket access place that we will subscribe. The connect method allows us to connect to any WebSocket url. As you can see we are missing the most important method here - create. This is the place where all the WebSocket — RxJS patching takes place.

private create(url): Rx.Subject<MessageEvent> {
let ws = new WebSocket(url);
    let observable = Rx.Observable.create(
(obs: Rx.Observer<MessageEvent>) => {
ws.onmessage = obs.next.bind(obs);
ws.onerror = obs.error.bind(obs);
ws.onclose = obs.complete.bind(obs);
            return ws.close.bind(ws);
}
);
    let observer = {
next: (data: Object) => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data));
}
},
};
    return Rx.Subject.create(observer, observable);
}

First we need to create new WebSocket. This is pretty well documented for example on the MDN WebSocket Guide. To create an RxJS subject we need to provide observable — that is the entity that will receive data from our socket and push it further to the subscribers. As you can see the interfaces are very similar so our job here is just to bind message to the next function, error to error function and close to complete function.

The second part of the Subject is the observer. Since we are using RxJS in version 5, the observer is just a prototype — not a regular class. This is why we minimally need to create plain JS object with one method — next(). This function will take care of sending information back to the WebSocket. We can do this after quick check if the WebSocket is still open.

This is the basic implementation of the WebSocket in the Angular2 world. If you’re interested about example usage, you can check out my sample Chat app created in GoLang on the backend and Angular2 on the frontend.

Client app: https://github.com/lwojciechowski/mildchat-client
Server app: https://github.com/lwojciechowski/mildchat-server

Update 2016–09–02
Recently Peter Kassenaar created lib based on this article. It’s RC6 compatibile: https://github.com/PeterKassenaar/ng2-websockets