Hello world with Cowboy and Websockets

Cowboy is a web server/framework written in Erlang, that provides pretty seamless websocket support.

The “getting started” guide is very good, and I’m going to assume you’ve read it, and followed it up to the “cowboy setup” section.

We’re going to add a ws handler, rather than an http one, using the template:

make new t=cowboy_ws n=ws_handler

And wire it up in the app:

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([{'_', [
        {"/connect", ws_handler, []} 
    Port = 8080,
    cowboy:start_http(my_http_listener, 100, [{port, Port}], [{env, [{dispatch, Dispatch}]}]),

You could now build and run the release, and connect to a websocket by calling http://localhost:8080/connect. But it wouldn’t be very interesting… yet.

The next job is to add a web page that will call the server, in priv/static/index.html:



var socket = new WebSocket('ws://localhost:8080/connect');
socket.onopen = function() {

and add a static handler to the dispatcher:

    Dispatch = cowboy_router:compile([{'_', [
        {"/", cowboy_static, {priv_file, ping_pong, "static/index.html"}},
        {"/connect", ws_handler, []} 

Still not hugely exciting, but if you look in the js console in your browser you should be connected to a websocket! We can now send a message to the server:

socket.onopen = function() {

function send(data) {
    console.log('Sending data: ' + data);

and return the standard response:

websocket_handle({text, <<"ping">>}, Req, State) ->
    Reply = {text, <<"pong">>},
    {reply, Reply, Req, State};

which we can listen for on the client:

socket.onmessage = function(ev) {
    console.log('Received data: ' + ev.data);

If all that went well, then we can liven things up by adding some json into the mix. First, add jiffy as a dependency (other json libraries are available!), then update the js to send some json instead:

socket.onopen = function() {
    var msg = {type: 'ping', count: 1};

and handle that on the server:

websocket_handle({text, Json}, Req, State) ->
    Map = jiffy:decode(Json, [return_maps]),
    Count = maps:get(<<"count">>, Map),
    Reply = #{type => <<"pong">>, count => Count + 1},
    {reply, {text, jiffy:encode(Reply)}, Req, State};

Just remember that the socket receives the json as text, you need to parse it!

socket.onmessage = function(ev) {
    console.log('Received data: ' + ev.data);
    var msg = JSON.parse(ev.data);

An alternative to parsing the json is to use pattern matching:

websocket_handle({text, <<"{\"type":\"ping\",\"count\":", Count:1/binary, "}">>}, Req, State) ->
    Reply = #{type => <<"pong">>, count => list_to_integer(binary_to_list(Count)) + 1}, 
    {reply, {text, jiffy:encode(Reply)}, Req, State};

but in this case, it has the disadvantage that the length of Count has to be specified.

You can find the source code for these examples here, and there’s another example in the Cowboy repo.


One thought on “Hello world with Cowboy and Websockets

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s