jtmoulia


Intro to Spell: An Elixir WAMP Client

I contracted with MyMeds&Me, a London based company focusing on pharmaceutical adverse event reporting and event capture, to build Spell.

A WAMP Client

The Web Application Messaging Protocol [WAMP] is an open messaging protocol designed by Tavendo GmbH. It specifies Publish Subscribe [PubSub] and Remote Procedure Call [RPC] functionality using a modular approach; peers must implement the basic protocol, but can negotiate advanced features. As an open specification, it supports polyglot, service oriented backends.

Spell's Purpose and Implementation

MyMeds&Me was interested in decoupling their backend and transitioning from Ruby to Elixir, which led them to WAMP. WAMP supports peers written in any language within the same distributed system, allowing which could implement or rewrite services in the most appropriate language. However, there was no WAMP client written in Elixir, i.e. no bridge for transitioning components over.

I worked with the MyMeds&Me engineering team to specify the requirements for an Elixir WAMP client, and flesh out the requirements into a technical plan and timeline. The work was split into two steps: first, the basic WAMP profile, and secondly, particular advanced features (e.g. challenge response authentication [CRA]) critical to their application. From initial design to completion, the project took less than two months.

Example

An involved PubSub example should make things more concrete. To make it more impressive, imagine that the publisher or subscriber are clients in other languages, running on different machines.

# Events must be published to a topic.
topic = "com.spell.example.pubsub.topic"

# Create a peer with the subscriber role.
subscriber = Spell.connect(Crossbar.uri,
                           realm: Crossbar.get_realm(),
                           roles: [Spell.Role.Subscriber])

# `call_subscribe/2,3` synchronously subscribes to the topic.
{:ok, subscription} = Spell.call_subscribe(subscriber, topic)

# Create a peer with the publisher role.
publisher = Spell.connect(Crossbar.uri,
                          realm: Crossbar.get_realm(),
                          roles: [Spell.Role.Publisher])

# `call_publish/2,3` synchronously publishes a message to the topic.
{:ok, publication} = Spell.call_publish(publisher, topic)

# `receive_event/2,3` blocks to receive the event.
case Spell.receive_event(publisher, subscription) do
  {:ok, event}     -> handle_event(event)
  {:error, reason} -> {:error, reason}
end

# Cleanup.
for peer <- [subscriber, publisher], do: Spell.close(peer)

Comments

There was another WAMP client written in Erlang, awre. While awre is a fine solution, we decided to implement a new client to take advantage of Elixir's extensibility and ecosystem. Spell uses Elixir libraries and tools where possible.

Elixir was a great fit for development. Erlang's message passing architecture and failure handling is a natural fit for network applications. Overlaid with Elixir's extensibility (metaprogramming and protocols, anyone?) we had a client which supported synchronous and asynchronous styles of programming, and could be easily extended to support WAMP's serialization and transport options. You can read more about it in the README.

Written by

Tags:

Published:

Modified: