REST API Beta Features
The contents of this section are beta features of our REST API. Although many of these features are fully functional, until the feature is released as generally available, the APIs may change. We recommend customers get in touch if they want to use these features in production.
Batch requests
Batch mode is a way of querying an API multiple times with a single HTTP request. The simplest example to consider is publishing a single message to multiple channels; a single request is made, indicating the channels and the contents of the message, and the system attempts to publish on all channels in parallel. Each of those attempts may succeed or fail independently. The batch mode API provides a way for the results of that request to be indicated back to the caller.
Generic operation
A batch mode request translates a single set of request details (ie the request body, params and headers) in to an array of requests for the underlying API. Each of those requests is then performed in parallel.
Once each request has completed, the batch-mode response is formulated to be returned to the caller. There are three possible outcomes:
- all requests succeeded. This is of course the expected case. The response is then an array containing the responses to the constituent queries in request order.
- the batch request failed prior to attempting the constituent API calls. This could typically be an authorisation failure, an invalid request, or some required element of the service being unavailable. The response is then an error response, with the applicable status code and error response body (with
message
,code
and any other relevant error information). - one or more constituent API calls failed. In this case the response contains a generic
400
status code and the response body contains an error object with a specific error code40020
signifying an error in a batch operation. The error body also then contains abatchResponse
property which in an array, in request order, containing the outcome of each of the constituent API calls.This means that caller can usually make the call and have access to the success result or an error in the case of failure. In the case of a partial failure, many callers may just wish to know whether or not the call succeeded fully, in which case they do not need to look at the
batchResponse
detail. However, callers that wish to know the detail of the outcome of each call can discover this from thebatchResponse
.
All batch-mode api calls are limited to addressing at most 100 different channels per request.
All POST
/PUT
requests (such as bulk publish) are subject to a maximum request body size of 2MiB.
Bulk publish
The REST API has been extended to include batch-mode publish operations. The API concerned is:
POST /messages
This is the new bulk publish API which is implicitly a batch-mode API. This performs a publish in parallel of messages to channels specified in the request
body. Check out the code example below on how to do this with the request
method in the REST client library.
var ablyRest = new Ably.Rest({ key: '<loading API key, please wait>' })
var content = { "channels": [ "test1", "test2" ], "messages": { "data": 'myData' } }
ablyRest.request('post', '/messages', null, content, null,
function(err, response) {
if(err) {
alert('An error occurred; err = ' + err.toString());
} else {
alert('Success! status code was ' + response.statusCode);
}
});
Demo OnlyCopyCopied!
You can also use the REST API directly with the following:
curl -X POST https://rest.ably.io/messages \
-u "<loading API key, please wait>" \
-H "Content-Type: application/json" \
--data '{ "channels": [ "test1", "test2"],
"messages": {"data": "My test message text" } }'
Demo OnlyCopyCopied!
A single BatchSpec
is an object of the form:
{
channels: <channel names>,
messages: <messages>
}
CopyCopied!
where:
<channel names>
is a single channel nameString
, or anArray
of channel nameStrings
; and<messages>
is a singleMessage
, or anArray
ofMessages
.
The bulk publish endpoint accepts a request body containing either a single BatchSpec
object, or an array of BatchSpec
objects.
Therefore the following are all valid request bodies for a bulk publish request:
Using a single BatchSpec object
{
channels: ['a channel name, containing a comma', 'another channel name'],
messages: {data: 'My message contents'}
}
CopyCopied!
Using multiple BatchSpec objects in an array
[
{
channels: ['a channel name, containing a comma', 'another channel name'],
messages: {data: 'My message contents'}
},
{
channels: 'single channel',
messages: [
{data: 'My message contents'},
{name: 'an event', data: 'My event message contents'},
]
}
]
CopyCopied!
There is an obvious mapping from the request body to the array of individual publish requests.
The 100 channel limit caps the total number of different channels in the request, irrespective of how they are arranged. So if the same channel name occurs in multiple BatchSpec
objects in a single requests, it will contribute only one channel towards the limit.
The messages
array of each BatchSpec
is treated atomically (for each channel), and so subject to the usual max message size limits – the total size of all Messages
in the array must be less than the limit (64kiB for paid accounts, 16kiB for free accounts). If the total number of messages you want to publish to one channel adds up to more than that, you can just split the messages for that channel up into multiple batchspecs. All you lose is atomicity (that is, it is then possible that the Messages
from one batchspec will be accepted, and the other rejected).
Remember, the total size of each request body must be less than 2MiB.
Batch reponses
The request
POST /messages
{
channels: ['channel0', 'channel1', 'channel2'],
messages: {data: 'My test message text'}
}
CopyCopied!
would have the following possible outcomes:
Success:
status code: 201
response body:
[
{
"channel":"channel0",
"messageId":"w234r5t-fr5"
},
{
"channel":"channel1",
"messageId":"vde4sfc0p"
},
{
"channel":"channel2",
"messageId":"nh3exv8ih"
}
]
CopyCopied!
Common-cause failure:
status code: 401
response body:
{
"error": {
"message":"Token expired",
"statusCode":401,
"code":40140
}
}
CopyCopied!
Partial success:
status code: 400
response body
{
"error": {
"message": "Batched response includes errors",
"statusCode":400,
"code":40020
}
"batchResponse": [
{
"channel":"channel0",
"messageId":"w234r5t-fr5"
},
{
"channel":"channel1",
"messageId":"vde4sfc0p"
},
{
"channel":"channel2",
"error": {
"message": "Given credentials do not have the required capability",
"statusCode": 401,
"code": 40160
}
}
]
}
CopyCopied!
Batch presence
The REST API has been extended to include batch-mode presence operations. The API concerned is:
GET /presence
This an API to retrieve the presence state of multiple channels and is a batch-mode API. This performs a presence get in parallel on a set of channels specified in the request
params. Check out the code example below on how to do this with the request
method in the REST client library.
var ablyRest = new Ably.Rest({ key: '<loading API key, please wait>' })
var content = { "channel": <channel names> }
ablyRest.request('GET', '/presence', content, null, {}, function(err, response) {
if(err) {
alert('An error occurred; err = ' + err.toString());
} else {
alert('Success! status code was ' + response.statusCode);
}
});
Demo OnlyCopyCopied!
You can also use the REST API directly with the following:
curl -X GET https://rest.ably.io/presence?channel=<channel names> \
-u "<loading API key, please wait>"
Demo OnlyCopyCopied!
where:
<channel names>
is aString
of channel names separated by commas, or aString
of channel names separated by a givenseparator
.
Below is an example of a curl request which uses a separator
to separate channels channel,1
and channel,2
:
curl -X GET https://rest.ably.io/presence?channel,1!channel,2=&separator=! \
-u "<loading API key, please wait>"
Demo OnlyCopyCopied!
Batch responses
The request:
GET /presence
{
channel: 'channel0,channel1,channel2'
}
CopyCopied!
would have the following possible outcomes:
Success:
status code: 200
response body:
[
{
"channel":"channel0",
<a href="[">presence</a>
{"clientId": "user1", "action": "1"},
{"clientId": "user2", "action": "1"}
]
},
{
"channel":"channel1",
<a href="[">presence</a>]
},
{
"channel":"channel2",
<a href="[">presence</a>
{"clientId": "user2", "action": "1"},
{"clientId": "user3", "action": "1"}
]
}
]
CopyCopied!
Common-cause failure:
status code: 401
response body:
{
"error": {
"message":"Token expired",
"statusCode":401,
"code":40140
}
}
CopyCopied!
Partial success:
status code: 400
response body
{
"error": {
"message": "Batched response includes errors",
"statusCode":400,
"code":40020
}
"batchResponse": [
{
"channel":"channel0",
<a href="[">presence</a>
{"clientId": "user1", "action": "1"},
{"clientId": "user2", "action": "1"}
]
},
{
"channel":"channel1",
<a href="[">presence</a>]
},
{
"channel":"channel2",
"error": {
"message": "Given credentials do not have the required capability",
"statusCode": 401,
"code": 40160
}
}
]
}
CopyCopied!
Batch responses with the request method
When using the request method in a library, you’ll need to handle the potential responses for success, partial success, and failure.
For a response object response
, response.success
will be true if the batch presence was successful, or false
if at least one presence request failed. response.statusCode
will be 200 for complete success, 400 for partial success, and 401 for an expected failure. response.errorCode
will contain the Ably error code, and response.errorMessage
will contain details of the error.
For successful requests, response.items
will contain a list of the responses for each individual channel from which presence has been requested.
For partially successful requests, response.items.batchResponse
will contain a list of the individual channel’s results, be it an error or a success. You will know a partial success has occurred by the response.errorCode
, which will be 40020
.
Below would be an example of how to deal with these:
var ablyRest = new Ably.Rest({ key: '<loading API key, please wait>' })
var content = { "channel": "channel1,channel2" }
ablyRest.request('GET', '/presence', content, null, {}, function(err, response) {
if(err) {
// Throw error
} else {
if(response.success) {
// If complete success
for(i = 0; i < response.items.length; i++) {
// Each response item will be roughly of the style:
/*
{
"channel": "channel1",
"presence": [
{ "action": 1, "clientId": "CLIENT1" },
{ "action": 1, "clientId": "CLIENT2" }
]
}
*/
}
} else if(response.errorCode === 40020) {
// If partial success
for(i = 0; i < response.items[0].batchResponse.length; i++) {
// Each batchResponse item will either be the same as success if it succeeded, or:
/*
{
"channel": "channel1",
"error": {
"code": 40160,
"message": "ERROR_MESSAGE",
"statusCode": 401
}
}
*/
}
} else {
// If failed, check why
console.log(response.errorCode + ', ' + response.errorMessage);
}
}
});
Demo OnlyCopyCopied!