Publish/Subscribe messaging app

The Ably Realtime service organizes the message traffic within applications into named channels. Channels are the “unit” of message distribution; clients attach to any number of channels to subscribe to messages, and every message published to a channel is broadcasted to all subscribers. This scalable and resilient messaging pattern is commonly called pub/sub.

As you can publish a message to any channel, channels provide a means for you to filter data by topic or enforce access control for your subscribers. Only subscribers for those channels will receive those messages.

Messages published can contain string, JSON object, JSON array or binary data payloads.

Publishing and subscribing for messages on channels with our channel API is trivial. Let’s get started.

Step 1 – Create your Ably app and API key

To follow this tutorial, you will need an Ably account. Sign up for a free account if you don’t already have one.

Access to the Ably global messaging platform requires an API key for authentication. API keys exist within the context of an Ably application and each application can have multiple API keys so that you can assign different capabilities and manage access to channels and queues.

You can either create a new application for this tutorial, or use an existing one.

To create a new application and generate an API key:

  1. Log in to your Ably account dashboard
  2. Click the “Create New App” button
  3. Give it a name and click “Create app”
  4. Copy your private API key and store it somewhere. You will need it for this tutorial.

To use an existing application and API key:

  1. Select an application from “Your apps” in the dashboard
  2. In the API keys tab, choose an API key to use for this tutorial. The default “Root” API key has full access to capabilities and channels.
  3. Copy the Root API key and store it somewhere. You will need it for this tutorial.

    Copy API Key screenshot

Step 2 – Install AblyStep 2 – Setup an Xcode project and install AblyStep 2 – Set up environment and install Ably

To start using Ably in your JRE application, you need to include the Ably Client library. We recommend that you include the latest client library via Gradle in your project’s gradle.build file.

apply plugin: 'application'
mainClassName = 'io.ably.tutorial.Example'

repositories {
  jcenter()
}

dependencies {
    compile 'io.ably:ably-java:1.2.0'
}

In the above example a specific version of the library is referenced, however we recommend you check which is the latest stable version and always use that. Follow link to get the latest stable release for Java.

After you add necessary dependencies, you can import AblyRealtime class into your code and initialize it.

import io.ably.lib.realtime.AblyRealtime;

public class Example {
  private final static String API_KEY = "INSERT-YOUR-API-KEY-HERE";

  public static void main(String[] args) {
      try {
          initAbly();
      } catch (AblyException e) {
          e.printStackTrace();
      }
  }

  private static void initAbly() throws AblyException {
      AblyRealtime ablyRealtime = new AblyRealtime(API_KEY);
  }
}

See this step in Github

To build your own Android Project, please visit Android Developers website and get familiar with steps necessary to set up your own application.
To start using Ably in your Android app, you need to include the Ably Client library. We recommend that you include the latest client library via Gradle in your module-level gradle.build file.

apply plugin: 'com.android.application'
...
dependencies {
    ...
    compile 'io.ably:ably-android:1.2.0'
}

In the above example a specific version of the library is referenced, however we recommend you check which is the latest stable version and always use that. Follow link to get the latest stable release for Android.

After you add necessary dependencies, you can import AblyRest class into your code and initialize it.

import io.ably.lib.realtime.AblyRealtime;

public class ExampleActivity extends AppCompatActivity {
  private final static String API_KEY = "INSERT-YOUR-API-KEY-HERE";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_example);
      try {
          initAbly();
      } catch (AblyException e) {
          e.printStackTrace();
      }
  }

  private void initAbly() throws AblyException {
      AblyRealtime realtime = new AblyRealtime(API_KEY);
  }
}

See this step in Github

Create a blank HTML page called example.html, to host your web app:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Ably Pub Sub</title>
  </head>
  <body>
  </body>
</html>

To start using Ably in your web app, you first need to include the Ably client library. In this example, we recommend that you include the latest client library from our CDN using a simple <script> tag. You should then instantiate the client library with the API key you copied in Step 1.

Note: in production we recommend you always use the token authentication scheme for browser clients, however in this example you will use an API key for simplicity.

Include the code below just before your closing </html> tag. This code uses the Promise-based version of the Ably client library (Ably.Realtime.Promise) that enables you to use the much tidier await/async syntax, instead of relying on callbacks:

<script src="https://cdn.ably.com/lib/ably.min-1.js"></script>
<script>
  const apiKey = "YOUR_API_KEY";
  const realtime = new Ably.Realtime.Promise(apiKey);
</script>

To start using Ably you first need to install the NPM module. The NPM module can be installed as follows:

npm install ably

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

Add the following to a file named example.js to instantiate the Ably library inside your Node.js server:

var Ably = require("ably");
var realtime = new Ably.Realtime({ key: apiKey });

See this step in Github

To start using Ably you first need to install the Ably RubyGem. The RubyGem can be installed as follows:

gem install ably

Or if using bundler, simply add the following to your Gemfile and run bundle install:

gem 'ably'

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

The Ruby realtime library uses EventMachine to run the client library within an asynchronous event loop. However, typically when using Ruby on servers, most developers use the synchronous REST client library API. As this tutorial needs realtime access to subscribe to messages, it uses the Ruby realtime library.

Add the following to a file named example.rb to instantiate the Ably library inside an EventMachine reactor:

require 'ably'
EventMachine.run do
  ably = Ably::Realtime.new(key: api_key)
end

See this step in Github

To start using Ably you first need to install composer package on packagist into your composer.

composer require ably/ably-php --update-no-dev

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

PHP Client library doesn’t provide Realtime API support, so we’ll create a web app that uses JavaScript on the client-side (browser) to demonstrate a server publishing messages to realtime JavaScript clients.

JavaScript will handle subscribing to messages, while PHP will be responsible for publishing messages.

First let’s create ably.php where we will store Ably library and Api key

<?php
require_once 'vendor/autoload.php';
$apikey = '{{ApiKey}}';
$ably   = new \Ably\AblyRest($apikey);

Next step is to create frontend of our app, and set up JavaScript library. create index.php file with code:

<?php
require_once 'ably.php';
?>
<html>
  <head>
    <script src="https://cdn.ably.com/lib/ably.min-1.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>Publish &amp; Subscribe sample</h1>
  </body>
  <script type="text/javascript">
    /* Set up a Realtime client which will subscribe to the 'sport' channel*/
    var realtime = new Ably.Realtime('<?= $apikey?>');
  </script>
</html>

If you would like to try running the server now, you can do so with php -S 0.0.0.0:8000. Once running, open your browser to http://localhost:8000/ and you should see “Publish & Subscribe sample”.

See this step in Github

To start using Ably you first need to install The REST library for Python, it’s hosted on Github and is published on PyPI and can be installed as follows:

pip install ably

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

Python Client library doesn’t provide Realtime API support, so we’ll create a web app that uses JavaScript on the client-side (browser) to demonstrate a server publishing messages to realtime JavaScript clients.

JavaScript will handle subscribing to messages, while Python will be responsible for publishing messages.

web.py is a simple web framework for Python. Django is arguably more popular as a web server framework, however for the purposes of this tutorial it is overkill.

Let’s get going with a simple web.py web server now. Install web.py using pip:

pip install web.py

Now set up a vanilla web.py server in server.py:

from __future__ import unicode_literals
from ably import AblyRest
import web

apiKey = '{{ApiKey}}'
client = AblyRest(apiKey)

render = web.template.render('templates/')

class index:
    def GET(self):
        return render.index(apiKey)

urls = (
    '/', index
)

app = web.application(urls, globals())

if __name__ == "__main__":
    app.run()

In web.py each resource is mapped to a class, which in turn takes action depending on HTTP method used. In this case it’s main domain '/', that will be handled by index class, and it will support HTTP GET.

We’ve used web.py template system to easily pass apiKey to JavaScript library, let’s create index.html in templates directory:

$def with (apiKey)
<html>
  <head>
    <script src="https://cdn.ably.com/lib/ably.min-1.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>Publish &amp; Subscribe sample</h1>
  </body>
  <script type="text/javascript">
    /* Set up a Realtime client which will subscribe to the 'sport' channel*/
    var realtime = new Ably.Realtime('$apiKey');
  </script>
</html>

Note on string encodings

Since Ably supports both string and binary payloads, to avoid ambiguity, we recommend that strings passed to the library for publishing to Ably (eg as an event name or payload data) should be unicode strings. In Python 3 this is the normal string type, but in Python 2 it is not, so we suggest you prefix string literals with u prefix (eg u'eventname' – or alternatively, use from __future__ import unicode_literals, which will make this automatic), and to explicitly decode any user input (eg raw_input().decode(sys.stdin.encoding).

If you would like to try running the server now, you can do so with python server.py. Once running, open your browser to http://localhost:8080/ and you should see the text “Publish & Subscribe sample”. If you would like to change port, on which your site will be available, simply add it after command ieg. python server.py 1234 for port 1234.

See this step in Github

We will start by creating an Xcode project for this tutorial. To build your own Xcode Project in Swift visit Apple developer website and get familiar with steps necessary to setup your own application.
When you setup your application delete the default ViewController.swift add new File → New → File… and choose Cocoa Touch Class.

Create new Cocoa Touch Class

Name your new class “ExampleViewController” and choose Swift as language:

Name new Cocoa Touch Class

After that navigate to Main.storyboard in your project, click on the ViewController that has already been added by default during project creation and from the Utilities that are located on the right choose Identity Inspector. Find the field labeled “Class” and select “ExampleViewController”.

Interface design

See this step in Github

To start using Ably you first need to install the Ably pod via CocoaPods. You need to add a Podfile to your project directory:

touch Podfile

Then add this line to your application’s Podfile:

pod 'Ably'

Install it with:

pod install

To learn more about using CocoaPods in your project visit official CocoaPods guide.

Then in your files in which you will be using Ably import:

import Ably

To connect to Ably, you need to instantiate the client library with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

Add the following to the file in which you imported the Ably library:

let API_KEY = "INSERT-YOUR-API-KEY-HERE"
let client = ARTRealtime(key: API_KEY)

See this step in Github

To start using Ably you first need to install the Ably Go library with the following command:

go get -u github.com/ably/ably-go/ably

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

Add the following to a file named example.go to instantiate the Ably library:

package main

import "fmt"
import "github.com/ably/ably-go/ably"

func main() {
    client, err := ably.NewRealtimeClient(ably.WithKey("INSERT-YOUR-API-KEY-HERE"))
    if err != nil {
      panic(err)
    }
}

All this is doing is instancing the Ably library, using an API key as your credentials.

See this step in Github

Step 3 – Subscribe to messages

Now that the library is installed, you can subscribe to messages published on channels. Every app can have an arbitrary number of channels that should be used to filter the messages received by subscribing clients. For example, if building a news feed, you may want one channel for politics named “politics”, and another for sport named “sport”. A user interested in “sport” can subscribe to the “sport” channel to receive updates. If that user is not subscribed to the “politics” channel, then “politics” updates will not be delivered to that user.

Channel channel = realtime.channels.get("sport");
channel.subscribe(new Channel.MessageListener() {
    @Override
    public void onMessage(Message messages) {
        System.out.println("Message received: " + messages.data);
    }
});

See this step in Github

Channel channel = realtime.channels.get("sport");
channel.subscribe(new Channel.MessageListener() {
    @Override
    public void onMessage(Message messages) {
        Toast.makeText(getBaseContext(), "Message received: "
              + messages.data, Toast.LENGTH_SHORT).show();
    }
});

See this step in Github

Create an async function called doPubSub() and then call that function at the end of your <script> block:

async function doPubSub() {
  // Write your Ably code here
}

doPubSub();

Ensure that you are connected to the Ably platform, by monitoring the connected event:

async function doPubSub() {
  await realtime.connection.once("connected");
  console.log("Connected to Ably!");
}

Use realtime.channels.get to get a reference to the “sport” channel. Then, subscribe to the channel:

async function doPubSub() {
  await realtime.connection.once("connected");
  console.log("Connected to Ably!");

  const channel = realtime.channels.get("sport");

  await channel.subscribe((msg) => {
    console.log("Received: " + JSON.stringify(msg.data));
  });
}

Test this by opening the example.html page in a browser tab. Any messages sent to the “sport” channel are logged to the browser console.

var channel = realtime.channels.get("sport");
channel.subscribe(function(msg) {
  console.log("Received: " + JSON.stringify(msg.data));
});

See this step in Github

channel = ably.channels.get('sport')
channel.subscribe do |msg|
  puts "Received: #{msg.data}"
end

See this step in Github

Update index.php and add code below before </script> tag:

var channel = realtime.channels.get("sport");
channel.subscribe(function(msg) {
  alert("Received: " + msg.data);
});

See this step in Github

Update index.html and add code below before </script> tag:

var channel = realtime.channels.get("sport");
channel.subscribe(function(msg) {
  alert("Received: " + msg.data);
});

See this step in Github

If you have not previously had experience building a basic user interface in Xcode, please refer to Apple developer guide on how to build a simple UI and also learn more about adding IBOutlets and IBActions.
To be able to subscribe to a channel and send some initial messages, we will add a listener for new messages and add a button that publishes a message. Go to your ExampleViewController and add a UIButton from Object library. Name the action “subscribeAction”.

Binding UI objects

In a similar fashion add two UILabels and connect one of them so that it will show the last message received. Name it “receivedMessageText”.
Your ExampleViewController should look similar to this view:

Binding UI objects

Add this code to previously added IBAction:

let channel = client.channels.get("sport")
self.receivedMessageText.text = ""

channel.subscribe { message in
    self.receivedMessageText.text = "\(message.timestamp) \(message.data)"
  }
}

See this step in Github

Update the main function in example.go to the following:

func main() {
    client, err := ably.NewRealtimeClient(ably.WithKey("INSERT-YOUR-API-KEY-HERE"))
    if err != nil {
      panic(err)
    }

    channel := client.Channels.Get("sport")

    _, err := channel.SubscribeAll(context.Background(), func(msg *ably.Message) {
      fmt.Printf("Received message with data '%v'\n", msg.Data)
    })
    if err != nil {
      err := fmt.Errorf("subscribing to channel: %w", err)
      fmt.Println(err)
    }
}

Now whenever a message is sent onto the sport Ably Channel, it’ll be received by our subscription.

See this step in Github

Step 4 – Publish a message

Publishing a message on a channel ensures that any number of subscribers on that channel receive the message in real time. To publish a message on the “sport” channel, call the publish method on the channel, specify an optional message event name as the first argument, and provide the payload as the second argument.

Channel channel = realtime.channels.get("sport");
channel.publish("update", "{ \"team\": \"Man United\" }", new CompletionListener() {
    @Override
    public void onSuccess() {
        System.out.println("Message sent");
    }

    @Override
    public void onError(ErrorInfo reason) {
        System.out.println("Message not sent, error occurred: "
              + reason.message);
    }
});

See this step in Github

Channel channel = realtime.channels.get("sport");
channel.publish("update", "{ \"team\": \"Man United\" }", new CompletionListener() {
    @Override
    public void onSuccess() {
        Toast.makeText(getBaseContext(), "Message sent",
        Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onError(ErrorInfo reason) {
        Toast.makeText(getBaseContext(), "Message not sent, error occurred: "
              + reason.message, Toast.LENGTH_SHORT).make();
    }
});

See this step in Github

Add the call to channel.publish to the last line of code within the doPubSub() function:

async function doPubSub() {
  await realtime.connection.once("connected");
  console.log("Connected to Ably!");

  const channel = realtime.channels.get("sport");

  await channel.subscribe((msg) => {
    console.log("Received: " + JSON.stringify(msg.data));
  });

  await channel.publish("update", { team: "Man United" });
}

Then, refresh the example.html page in your browser and watch the message payload being displayed in the browser console.

var channel = realtime.channels.get("sport");
channel.publish("update", { "team": "Man United" });

See this step in Github

channel = ably.channels.get('sport')
channel.publish 'update', 'team' => 'Man United'

See this step in Github

Create publish.php file which will be responsible for publishing messages:

<?php
require_once 'ably.php';
if (isset($_POST['message']) && !empty($_POST['message'])) {
    $channel = $ably->channels->get('sport');
    $channel->publish('update', $_POST['message']);
}
?>
<html>
  <body>
    <h1>Input message</h1>
    <form method="post">
      <input type="text" name="message">
      <input type="submit" value="Publish!">
    </form>
  </body>
</html>

And to simplify it even further, let’s add an iframe so that we can publish messages from the same browser window. Add code below just after the <h1>Publish & Subscribe sample</h1>:

<iframe src="publish.php"></iframe>

If you would like to try running the server now, you can do so with php -S 0.0.0.0:8000. Once running, open your browser to http://localhost:8000/ and you should see “Publish & Subscribe sample” and box with “input message”, try it out.

See this step in Github

Let’s create resource for /publish, it will serve as message publisher:

class publish:
    def GET(self):
        return render.publish()

    def POST(self):
        message = web.input().get('message')
        if message is not None:
            channel = client.channels.get('sport')
            channel.publish('update', message)
        raise web.seeother('/publish')

And create publish.html in templates directory with message form:

<html>
  <body>
    <h1>Input message</h1>
    <form method="post">
      <input type="text" name="message">
      <input type="submit" value="Publish!">
    </form>
  </body>
</html>

And to simplify it even further, let’s add an iframe so that we can publish messages from the same browser window. Add code below to index.html, just after the <h1>Publish & Subscribe sample</h1>:

<iframe src="/publish"></iframe>

Let’s update urls:

urls = (
    '/', index,
    '/publish', publish
)

If you would like to try running the server now, you can do so with python server.py. Once running, open your browser to http://localhost:8080/ and you should see the text “Publish & Subscribe sample” and box with “input message”, try it out.

See this step in Github

In this step add another UIButton and bind it to action named “publishAction”. Also, add one more UILabel and an UITextField – bind it in your code as “messageText” . Thanks to that users will be able to write their own messages.
Your view should now look like this:

Binding UI objects

You can also check if an error occurred while sending the message.
Add this code to previously added IBAction:

channel.publish("update", data: messageText.text) { error in
  guard error == nil else {
    return self.showAlert("Error", message:
                          "There was an error while sending the message. \(error)")
  }
}

See this step in Github

To add publishing, change our main function to be the following:

func main() {
    client, err := ably.NewRealtimeClient(ably.WithKey("INSERT-YOUR-API-KEY-HERE"))
    if err != nil {
      panic(err)
    }

    channel := client.Channels.Get("sport")

    _, err := channel.SubscribeAll(context.Background(), func(msg *ably.Message) {
      fmt.Printf("Received message with data '%v'\n", msg.Data)
    })
    if err != nil {
      err := fmt.Errorf("subscribing to channel: %w", err)
      fmt.Println(err)
    }

    res, err := channel.Publish("team", "Man United")
    // await confirmation of publish
    if err = res.Wait(); err != nil {
        panic(err)
    }
}

Due to the range iteration across sub.MessageChannel() being a blocker, we’re adding our publish code inbetween that and our actual channel.Subscribe().

See this step in Github

You have now learned how to instantiate the Ably client, subscribe to a channel, and publish messages on that channel.

Download tutorial source code

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-java

Then you can run project inside your console. Be sure to switch into the project’s directory and then use these commands in your terminal:

./gradlew assemble
./gradlew run

Don’t forget to replace your ExampleActivity#API_KEY field with Ably API key.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-android

And then run the demo on your Android device. Check Android Developers website if you are not familiar on how to run an Android Project. Don’t forget to replace your ExampleActivity#API_KEY field with Ably API key.

The solution code for this tutorial is available on Github.

To run the demo, perform the following tasks:

1. Clone the repo locally:

git clone https://github.com/ably/tutorials.git

2. Add your Ably API key to example.html by replacing YOUR_ABLY_API_KEY with your own API key.
3. In a new browser tab, open your browser’s developer tools.
4. Open the example.html file in the browser tab and inspect the console output.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-nodejs

And then run the demo locally by adding your Ably API key to example.js and running the demo node example.js

The complete source code for each step of this tutorial is available on Github

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-ruby

And then run the demo locally by adding your Ably API key to example.rb and running the demo bundle exec ruby example.rb

The complete source code for each step of this tutorial is available on Github

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-php

And then run the demo locally by adding your Ably API key to ably.php, install composer dependencies with:

composer install

and run the web server php -S 0.0.0.0:8000.

The complete source code for each step of this tutorial is available on Github

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-swift

In the project directory simply run:

pod install

Open example.xcworkspace and build the demo on your preferred iPhone simulator or device. Don’t forget to replace your ExampleViewController#API_KEY field by adding your Ably API key to ExampleViewController.swift.

The complete source code for each step of this tutorial is available on Github

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-python

And then run the demo locally by adding your Ably API key to server.py, install the required libraries:

pip install ably web.py

And run the web server python server.py.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout publish-subscribe-go

And then run the demo locally by adding your Ably API key to example.go and running the demo go run example.go

Next steps

1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime channels and messages documentation
2. Learn more about Ably features by stepping through our other Ably tutorials
3. Gain a good technical overview of how the Ably realtime platform works
4. Get in touch if you need help