Over the last few months we've been working on a
new version 2 of the RapidPro API. The main goal of this API release is to limit users to operations which we know we can make performant at scale. Some of the filtering options we have allowed in API v1 work fine with millions of messages but become slow against a database of 100s of millions of messages. RapidPro needs an API which is always fast.
We've also been able to clean up parameter names etc, so the interface is now a bit more consistent across different endpoints. And we've put some thoughts into ensuring this API version will be future proof with potential changes to the flow spec etc.
Now that API v2 is released, API v1 is deprecated and will be removed on March 1st 2017.
Developers using API v1 should start migrating to API v2. If you are using the official Python client then it should be relatively easy to make the switch. For example:
from temba_client.v1 import TembaClient
for contact in client.get_contacts():
Becomes...
from temba_client.v2 import TembaClient
for contact in client.get_contacts().all():
Changes To Look Out For..
If you are migrating code which uses the API then be sure to check the
API v2 documentation for each endpoint, as we can't list all the little changes here - but below are the general changes to look out for:
- All operations which list objects use cursor pagination rather than the typical Django page=1,.. etc pagination. This means we do not return a total count value for result sets. Count values tend to be expensive to calculate on very large datasets so this was not sustainable as databases grow.
- Filtering options are limited to single values, e.g. in v1 you could fetch runs like runs.json?id=1131241,436364,464363,... but now id can only be a single value. If you find yourself needing to fetching lots of objects repeatedly, then it may be better to restructure your code so that you fetch all objects of that type as they are created or modified.
- When updating objects the identifier is sent as a query string param rather than a field in the JSON body. This is more RESTful and makes POSTs more consistent with GETs and DELETEs, e.g. changing a contact's name:
POST contacts.json
{
"uuid": "1c904f04-af6f-4f2b-89e1-9ebf0c5aef73",
"name": "Bob"
}
Becomes...
POST contacts.json?uuid=1c904f04-af6f-4f2b-89e1-9ebf0c5aef73
{
"name": "Bob"
} - Status code usage is more consistent. In v1 the status code 201 was used for both successful create operations and update operations. Trying to update a non-existent object returned 400 but trying to delete the same object returned 404. In v2 the rules for status codes are:
- 200: A list or update request was successful
- 201: A resource was successfully created (only returned for POST requests)
- 204: An empty response - used for both successful DELETE requests and POST requests that update multiple resources.
- 400: The request failed due to invalid parameters. Do not retry with the same values, and the body of the response will contain details.
- 403: You do not have permission to access this resource
- 404: The resource was not found (returned by POST and DELETE methods)
- Objects are referenced in more consistent ways:
- messages, runs and broadcasts are always referenced by their id value
- contact fields by their key
- groups and labels by name or UUID
- everything else is referenced by its UUID
- Date time values are always returned with microsecond accuracy (v1 used only millisecond accuracy)
- Phone numbers must now always include the country codes, i.e. we can't accept a URN like "tel:0964153001" but we will accept "tel:+260964153001". In the past we tried to infer the country from the channels installed on an account but this isn't reliable so we don't do it for v2 requests.
- The message bulk action endpoint is limited to 100 messages, so if you need to update more messages than that, make sure you batch your requests.
- Old names for things are gone. In v1 messages could sometimes be sms, channels could be relayers. In v2 it's always messages and channels.
- All endpoints are rate limited. If you are making lots of requests then expect to get some 429 responses. These will include a Retry-After header which provides a number of seconds to wait before retrying. If you are using the official Python client, you can pass retry_on_rate_exceed to some of its methods to have it automatically wait and retry if this happens.
If you have any questions about migrating to v2, don't hesitate to ping us here.
-Rowan