Hermes: an open source implementation of Publish/Subscribe engine

I’m glad to announce Hermes, a new open source project developed by TellagoDevLabs. It implements a Publish/Subscribe pattern exposed through a RESTFull API  and MongoDB as backend for storage.

Hermes allows us to create Topics and then Publishers and Subscribers will be able to publish and retrieve messages for a specific Topic.

Hermes is message agnostic, that means that it doesn’t care about what the message contains and its data type.

Its RESTFull interface allows us to interact with Hermes using plain HTTP request. The example below shows us how to publish the string “Hello Hermes!” for a Topic (In this example the Topic’s ID is ‘4e1aeec5e892e70b044c695c’)

To publish the message we should:

  1. Create a HttpWebRequest
  2. Set request’s method to POST
  3. Complete the Content-Type Header with a valid value, in this case it will be ‘text/text’
  4. Set Request’s body with the message, in this case it will be ‘Hello Hermes!’ but you can set any stream as message’s body.
  5. Optionally, you can add custom HTTP headers, in this sample I added a header named ‘Foo’
// Create HTTP POST request var request = (HttpWebRequest)WebRequest.Create("http://localhost:6156/messages/topic/4e1aeec5e892e70b044c695c");
request.Method = "POST";

// Add Body and Content-Type header to the Request request.ContentType = "text/text";
using (var stream = request.GetRequestStream())
    using (var writer = new StreamWriter(stream))
        writer.Write("Hello Hermes!");

// Add a custom header to the request request.Headers.Add("foo","some data");

// Publish the message var response = (HttpWebResponse)request.GetResponse();

// Displays HTTP status code and message's url. Console.WriteLine("HttpStatusCode: {0}", response.StatusCode);
Console.WriteLine("Header Location: {0}", response.Headers["Location"]);


When Hermes processes the request, it store the request’s body an all request’s headers, and after that it returns a HTTP response with status code 201 CREATED, and the Location HTTP header containing the URL to the message just published.

We can retrieve the message sending an HTTP GET request to the URL receive at Location header:

// Create HTTP GET request to Retrieve the message request = (HttpWebRequest)WebRequest.Create(response.Headers["Location"]);
request.Method = "GET";

// Send the request response = (HttpWebResponse)request.GetResponse();

Console.WriteLine("Retrieving message");
Console.WriteLine("Foo header: {0}", response.Headers["Foo"]);
Console.WriteLine("Message body: {0}", new StreamReader(response.GetResponseStream()).ReadToEnd());

Or we can retrieve all the messages for a specific topic sending an HTTP GET request to the Topic’s URL. The response will contain an array of links to each topic’s message:

// Create HTTP GET request request = (HttpWebRequest)WebRequest.Create("http://localhost:6156/messages/topic/4e1aeec5e892e70b044c695c");
request.Method = "GET";

// send request response = (HttpWebResponse)request.GetResponse();

Console.WriteLine("Polling topic's messages");

var contentAsString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var content = XDocument.Parse(contentAsString);

I ran the sample above against a Topic that contains two messages, below is its output:


In future posts I will write about the Client API that we created in order to simplify consuming Hermes.

You can find the complete source code here and its documentation  here. And you can also find more information in these blogs: