Warning: You are viewing an old version (0.8) of this documentation. We recommend you view the latest version 1.2.
REST Client Library API

Channels and Messages

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

Getting started

The Ably REST client library provides a straightforward API for publishing and retrieve history messages on a channel.

var rest = new Ably.Rest('xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c');
var channel = rest.channels.get('lip-say-pet');
channel.publish('example', 'message data', function() {
  channel.history(function(err, resultPage) {
    console.log('Last published message:' + resultPage.items[0]);
  });
});
var rest = new Ably.Rest('xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c');
var channel = rest.channels.get('lip-say-pet');
channel.publish('example', 'message data', function() {
  channel.history(function(err, resultPage) {
    console.log('Last published message:' + resultPage.items[0]);
  });
});
rest = Ably::Rest.new('xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c')
channel = rest.channels.get('lip-say-pet')
channel.publish 'example', 'message data'
result_page = channel.history()
puts "Last published message: #{result_page.items.first}"
rest = AblyRest('xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c')
channel = rest.channels.get('lip-say-pet')
channel.publish(u'example', u'message data')
result_page = channel.history()
print("Last published message data: " + result_page.items[0].data)
$rest = new Ably\AblyRest('xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c');
$channel = $rest->channels->get('lip-say-pet');
$channel->publish('example', 'message data');
$resultPage = $channel->history();
echo("Last published data: " . $resultPage->items[0]->data);
AblyRest rest = new AblyRest("xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c");
Channel channel = rest.channels.get("lip-say-pet");
channel.publish("example", "message data");
PaginatedResult<Message> resultPage = channel.history(null);
System.out.println("Last published message ID: " + resultPage.items[0].id);
AblyRest rest = new AblyRest("xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c");
IRestChannel channel = rest.Channels.Get("lip-say-pet");
await channel.PublishAsync("example", "message data");
PaginatedResult<Message> resultPage = await channel.HistoryAsync();
Console.WriteLine("Last published message ID: " + resultPage.Items[0].Id);
ARTRest *rest = [[ARTRest alloc] initWithKey:@"xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c"];
ARTRestChannel *channel = [rest.channels get:@"lip-say-pet"];
[channel publish:@"example" data:@"message data"];
[channel history:^(ARTPaginatedResult<ARTMessage *> *resultPage, ARTErrorInfo *error) {
    NSLog(@"Last published message ID: %@", resultPage.items[0].id);
}];
let rest = ARTRest(key: "xVLyHw.Kv8d5g:mBD48R-jAbz5AHn1XJmEz5AdYoFhYLPZmantwZAx49c")
let channel = rest.channels.get("lip-say-pet")
channel.publish("example", data: "message data")
channel.history { resultPage, error in
    print("Last published message ID: \(resultPage!.items[0].id)")
}

Channels

In order to publish, retrieve message history or access presence history, you must first obtain a REST channel instance.

Obtaining a channel instance

A Channel object is a reference to a single channel. A channel instance is obtained from the channels collection of the Rest::ClientAblyRestRest instance, and is uniquely identified by its unicode string name. Find out more about channel naming

var channel = rest.channels.get('channelName');
var channel = rest.channels.get('channelName');
Channel channel = rest.channels.get("channelName");
IRestChannel channel = rest.Channels.Get("channelName");
channel = rest.channels.get('channelName')
channel = rest.channels.get('channelName')
$channel = $rest->channels->get('channelName');
ARTRestChannel *channel = [realtime.channels get:@"channelName"];
let channel = realtime.channels.get("channelName")

To find out more about subscribing to messages published on channels in realtime, see the Realtime channel API.

Setting channel options and encryption

A set of channel options may also be passed to configure a channel for encryption. Find out more about symmetric message encryption.

Crypto.generateRandomKey(function(err, key) {
  var options = { cipher: { key: key } };
  var channel = rest.channels.get('channelName', options);
});
Crypto.generateRandomKey(function(err, key) {
  var options = { cipher: { key: key } };
  var channel = rest.channels.get('channelName', options);
});
CipherParams params = Crypto.getDefaultParams(key);
ChannelOptions options = new ChannelOptions();
options.encrypted = true;
options.cipherParams = params;
Channel channel = rest.channels.get("channelName", options);
CipherParams cipherParams = Crypto.GetDefaultParams(key);
ChannelOptions options = new ChannelOptions(cipherParams);
IRestChannel encryptedChannel = rest.Channels.Get("channelName", options);
key = Ably::Util::Crypto.generate_random_key
options = { cipher: { key: key } }
channel = rest.channels.get('channelName', options)
key = ably.util.crypto.generate_random_key()
channel = rest.channels.get('channelName', cipher={'key': key})
$key = Ably\Crypto->generate_random_key();
$options = array('cipher' => array('key' => key));
$channel = $rest->channels->get('channelName', $options);
NSData *key = [ARTCrypto generateRandomKey];
ARTChannelOptions *options = [[ARTChannelOptions alloc] initWithCipherKey:key];
ARTRestChannel *channel = [rest.channels get:@"channelName" options:options];
let key = ARTCrypto.generateRandomKey()
let options = ARTChannelOptions(cipherKey: key)
let channel = rest.channels.get("channelName", options: options)

Channel namespaces

One or more channel namespaces, or channel name prefixes, may be configured for an app in your dashboard. When a channel is created whose name is prefixed with one of the namespaces, the channel assumes certain configured attributes associated with that namespace. For example, a channel namespace named “private” would match channels named “private”, “private:chat”, “private:chat:mike”.

Namespace-prefixed channel names are delimited by a single colon :; the first component of the channel name (from the start up to and including the last character before the colon) is the namespace. A channel name may validly contain a colon even if the namespace component does not correspond to a namespace; also, a channel may contain multiple colons and only the component up to the first colon will be matched with a namespace. The only restriction on channel names is that a channel name may not start with a colon :, an open square bracket [ and it may not be empty.

Namespaces are defined and configured via the application dashboard settings. The namespace attributes that can be configured are:

  • Persisted messages – If enabled, all messages within this namespace will be stored according to the storage rules for your account. You can access stored messages via the history API
  • Require identification – if enabled, clients will not be permitted to subscribe to matching channels unless they are both authenticated and identified (they have an assigned client ID). Anonymous clients are not permitted to join these channels. Find out more about authenticated and identified clients
  • Require TLS – if enabled, only clients who have connected to Ably over TLS will be allowed to join the channel

Key or token capabilities can also specify access rights based on channel namespace, find out more about authentication

Messages

Each message published has an optional event name propertymemberattribute and a data propertymemberattribute carrying the payload of the message. Various primitive and object types are portably defined and supported in all clients, enabling clients to be interoperable despite being hosted in different languages or environments.

The supported payload types are Strings, JSON objects and arrays, plain c# objects which are converted to json, buffers containing arbitrary binary data, and Null objects. Client libraries detect the supplied message payload and encode the message appropriately.

Subscribing to messages

The REST client library does not offer message realtime subscription but instead provides access to the “live” history using the REST history API. Find out more about subscribing to messages in realtime using the Realtime API.

The name propertymemberattribute of published messages does not affect the distribution of a channel message to clients but may be used as a subscription filter, allowing a client to register a listener that only sees a subset of the messages received on the channel. Find out more about registering listeners using the Realtime API.

Publishing messages

Channels expose a publish method whereby a client can publish either a single message or an array of messages to a channel over REST.

channel.publish('event', 'This is my payload', function(err) {
  if(err) {
    console.log('Unable to publish message; err = ' + err.message);
  } else {
    console.log('Message successfully sent');
  }
});
channel.publish('event', 'This is my payload', function(err) {
  if(err) {
    console.log('Unable to publish message; err = ' + err.message);
  } else {
    console.log('Message successfully sent');
  }
});
channel.publish('event', 'This is my payload')
channel.publish(u'event', u'This is my payload')
$channel->publish('event', 'This is my payload');
channel.publish("event", "This is my payload");
channel.PublishAsync("event", "This is my payload");
[channel publish:@"event" data:@"This is my payload"];
channel.publish("event", data: "This is my payload")

Publishing on behalf of realtime connection

Message published using the REST API may be done so on behalf of an existing realtime connection when a valid connectionKey is present in the published message. For example, if you want to publish a message using the REST client library so that it appears to come from an existing connected realtime client, then the connection’s private (secret) connection key must be included. See a publish on behalf of a realtime client example.

If the connectionKey is invalid or belongs to a connection that has since been closed, then the publish operation will fail.

Retrieving message history

Channels expose a historyHistory method providing a means for clients to obtain messages previously sent on the channel. Channel history can be used to return continuous message history up to the exact point a realtime channel was attached.

History provides access to instantaneous “live” history as well as the longer term persisted history for attached channels. If persisted history is enabled for the channel, then messages will typically be stored for 24 – 72 hours. If persisted history is not enabled, Ably retains the last two minutes of message history in memory.

The following example retrieves the first two pages of historical messages published up until the point the channel was attached.

channel.history(function(err, resultPage) {
  if(err) {
    console.log('Unable to get channel history; err = ' + err.message);
  } else {
    console.log(resultPage.items.length + ' messages received in first page');
    if(resultPage.hasNext()) {
      resultPage.next(function(err, nextPage) { ... });
    }
  }
});
channel.history(function(err, resultPage) {
  if(err) {
    console.log('Unable to get channel history; err = ' + err.message);
  } else {
    console.log(resultPage.items.length + ' messages received in first page');
    if(resultPage.hasNext()) {
      resultPage.next(function(err, nextPage) { ... });
    }
  }
});
PaginatedResult<Message> resultPage = channel.history(null);
System.out.println(resultPage.items().length + " messages received in first page");
if(resultPage.hasNext()) {
  PaginatedResult<Message> nextPage = resultPage.next();
  System.out.println(nextPage.items().length + " messages received in second page");
}
PaginatedResult<Message> resultPage = await channel.HistoryAsync();
Console.WriteLine(resultPage.Items.Count + " messages received in first page");
if(resultPage.HasNext) {
  PaginatedResult<Message> nextPage = await resultPage.NextAsync();
  Console.WriteLine(nextPage.Items.Count + " messages received in second page");
}
result_page = channel.history
puts "#{result_page.items.length} messages received in first page"
if result_page.has_next?
  next_page = result_page.next
  puts "#{next_page.items.length} messages received in second page"
end
result_page = channel.history()
print str(len(result_page.items)) + ' messages received in first page'
if result_page.has_next():
  next_page = result_page.next()
  print str(len(next_page.items)) + ' messages received in second page'
$resultPage = channel->history();
echo(count($resultPage->items) . 'messages received in first page');
if($resultPage->hasMext()) {
  $nextPage = $resultPage.next();
  echo(count($resultPage->items) . 'messages received in second page');
}
[channel history:^(ARTPaginatedResult<ARTMessage *> *resultPage, ARTErrorInfo *error) {
  NSLog(@"%lu messages received in first page", (unsigned long)[resultPage.items count]);
  if (resultPage.hasNext) {
    [resultPage next:^(ARTPaginatedResult<ARTMessage *> *nextPage, ARTErrorInfo *error) {
      // ...
    }];
  }
}];
channel.history { resultPage, error in
  let resultPage = resultPage!
  print("\(resultPage.items.count) messages received in first page")
  if resultPage.hasNext {
    resultPage.next { nextPage, error in
      // ...
    }
  }
}

See the history documentation for further details of the supported query parameters.

Presence

Channels expose a presencePresence member which a client can use to obtain present members and presence event history for the channel itself. See the REST presence documentation for details.

API Reference

View the Messages API Reference.


Need help?

If you need any help with your implementation or if you have encountered any problems, do get in touch. You can also quickly find answers from our knowledge base, and blog.