REST APIs and Backlot
The following is an introduction to REST, particularly in the context of the Backlot API.
API Conventions
The following is shorthand notation for issue a GET HTTP request to https://api.ooyala.com/v2/players.
[GET] /v2/players
Content listed directly below the HTTP verb and the resource url is the body of the request. Request bodies should be JSON unless otherwise indicated. For example:
[POST] /v2/syndications
{
"name": "new youtube syndication",
"type": "youtube"
}
Fields that represent a variable (such as a player ID) are enclosed in curly braces.
[GET] /v2/players/{player_id}
REST Overview
The Backlot and Analytics APIs follow the conventions of REST design. Every resource in the API has its own URL. You can view, modify, and delete those resources ("nouns") by sending requests to the resource's URL and using standard HTTP methods ("verbs") in your requests.
All requests must be made using HTTPS.
The following are the standard HTTP methods that we use. Any HTTP library or tool will allow you to specify which one of these HTTP methods you want to use when making your request.
- GET: View a resource.
- POST: Create a new resource.
- DELETE: Delete a resource.
- PUT: Replace an existing resource.
- PATCH: Update or modify an existing resource.
Creation calls (such as POST to /v2/players
) can take all the same parameters as an update call (PATCH) to that resource.
When modifying resources using PATCH, PUT or POST requests, the body of the request should contain a JSON representation of the resource. For instance, issuing a GET request to view a player will look like
[GET] /v2/players/2kj390
The response is also in JSON:
{
"id": "2kj390",
"name": "my player",
"provider_homepage_url": "http://www.ooyala.com",
...
}
You could rename that player by sending a PATCH request to /v2/players/2kj390
with the following request body:
{
"name": "my new player name"
}
Sample Usage
You can make HTTP requests using any HTTP library for your programming language. These examples will use the unix command line tool curl to make requests.
This example gets the details for a player with an ID of NWI1ZmU4NDNmNmIyODY3ODA0NGNhNDZk
:
$ curl -X GET 'https://api.ooyala.com/v2/players/NWI1ZmU4NDNmNmIyODY3ODA0NGNhNDZk'\
'?api_key=ZnMmM6AO3C-iBubra3R2Xd6pXHgK.28riq&expires=1930294539'\
'&signature=p3RfmwGk%2FjwIup%2BUtyTtXjU%2FPpDx2DwHNGyfko07%2B28'
To modify one of the fields in this player resource, use a PATCH request. This example sets the "provider_homepage_url" for this player to be "http://www.ooyala.com". The "-d" flag of curl is being used here to specify the body of the request.
$ curl -X PATCH 'https://api.ooyala.com/v2/players/NWI1ZmU4NDNmNmIyODY3ODA0NGNhNDZk'\
'?api_key=ZnMmM6AO3C-iBubra3R2Xd6pXHgK.28riq&expires=1930294539'\
'&signature=sea6HjJuWCIXvrw4qxPYCidlMepq0UFu%2FQ9MM6Uw%2Fm4' \
-d '{ "provider_homepage_url": "http://www.ooyala.com" }'
HTTP response codes for Ooyala API requests
These are the HTTP response codes that can be returned for API responses. In case of errors, the API response body will explain the reason why the API returned an error response code.
200
(OK): Indicates that Ooyala successfully handled an HTTP GET request.400
(Bad request): Indicates that a request was poorly formed or contained invalid data. For example, the API would return a 400 response code if your request contained malformed JSON or if you tried to submit a start_time of "25:00:00" for a publishing rule since the hour field of time must be between 0 and 23.401
(Not authorized): Indicates that a request was not properly signed, or that the API key supplied was invalid.403
(Forbidden): Indicates that you have submitted a request that is not properly authenticated for the requested operation.404
(Not found): Indicates that you have tried to access a resource that does not exist. For example, you would receive a 404 response code if you tried to delete a player but you specified the wrong URL for the player.
Authenticating Your Requests
Every request made to Ooyala's APIs requires three querystring parameters for authentication:
- api_key: a user-specific key found in the Developers tab of Backlot.
- expires: a UNIX timestamp (seconds since Jan 1st, 1970) indicating when your request should be valid until.
- signature: a computed digest of all of your request's parameters, to ensure your request URLs cannot be tampered with after they have been signed.
What follows is an example of generating a signed GET request to https://api.ooyala.com/v2/players/HbxJKM
.
-
Start with your 40 character secret key. This can be found in the Developers tab in Backlot;
it is unique for each user and should always be kept secure and private.
For this example, we're going to use "329b5b204d0f11e0a2d060334bfffe90ab18xqh5" as the secret key.
329b5b204d0f11e0a2d060334bfffe90ab18xqh5
-
Append the HTTP method (e.g., GET, POST, PUT):
329b5b204d0f11e0a2d060334bfffe90ab18xqh5GET
-
Append the request path:
329b5b204d0f11e0a2d060334bfffe90ab18xqh5GET/v2/players/HbxJKM
-
Append any query string parameters, sorted alphabetically by keys.
Parameters should not be URL-encoded when appended to this string.
Remember to include the required
api_key
andexpires
parameters. In this example we'll use an api_key of7ab06
and an expiration of1299991855
.
329b5b204d0f11e0a2d060334bfffe90ab18xqh5GET/v2/players/HbxJKMapi_key=7ab06expires=1299991855
- If your request has a body (usually the case with PATCH and PUT requests, but not GET requests), append the entire request body to the string.
-
From this string, you can now generate a SHA-256 digest in Base64, truncate the string to 43 characters, and remove any trailing "=" signs. When appending this signature to your request URL, URL encode it (especially the "+", "=" and "/" characters).
This example produces a signature of
p9DG/+ummS0YcTNOYHtykdjw5N2n5s81OigJfdgHPTA
which, URL encoded, is
p9DG%2F%2BummS0YcTNOYHtykdjw5N2n5s81OigJfdgHPTA
-
Append this signature to your request URL as a querystring parameter. You can now visit this URL to make your request.
This is the final, signed URL:
https://api.ooyala.com/v2/players/HbxJKM?api_key=7ab06&expires=1299991855&signature=p9DG%2F%2BummS0YcTNOYHtykdjw5N2n5s81OigJfdgHPTA
Sample Code for Generating Signatures
This Ruby sample code can be used for generating signatures.
require "digest/sha2"
require "base64"
# Both of these values should be obtained from the Developers tab in Backlot.
API_KEY = ""
SECRET = ""
module OoyalaApi
def self.generate_signature(secret, http_method, request_path, query_string_params, request_body)
string_to_sign = secret + http_method + request_path
sorted_query_string = query_string_params.sort { |pair1, pair2| pair1[0] <=> pair2[0] }
string_to_sign += sorted_query_string.map { |key, value| "#{key}=#{value}"}.join
string_to_sign += request_body.to_s
signature = Base64::encode64(Digest::SHA256.digest(string_to_sign))[0..42].chomp("=")
return signature
end
end
# Example usage of the generate_signature function:
#
# Set `expires` in 1-hour intervals for higher caching performance:
# t = Time.now
# expires = Time.local(t.year, t.mon, t.day, t.hour + 1).to_i
#
# params = { "api_key" => API_KEY, "expires" => expires }
# signature = OoyalaApi.generate_signature(SECRET, "GET", "/v2/players/HbxJKM", params, nil)
Paging
Responses that include a list of first-class resources will return a paged result set. First-class resources are:
- Assets
- Labels
- Players
- Publishing Rules
- Syndications
Any response that lists these resources will return paged JSON in the following format.
A list of labels is represented here:
GET "/v2/labels"
{
items: [
{
"name": "Label 1",
"id": "61b70ba4ded34cc2a3e8096924fe6247",
"parent_id": null,
"full_name": "/Label 1"
},
{
"name": "Label 2",
"id": "3cadabc7066b48afa74f48d396f1f792",
"parent_id": null,
"full_name": "/Label 2"
}
],
"next_page": "/v2/labels?limit=200&page_token=%2FLabel+2"
}
The "next_page" URL parameters can be used in a subsequent signed request to retrieve the next page. In this example, I would sign a new request with the limit and page_token parameters added.
You may specify any limit between 1 and 500 for paged requests. The default is 100.
For example, the below issues a request for labels with a page size of 1:
[GET] /v2/labels?limit=1
You can use the next_page
URL to request the next page:
[GET] /v2/labels?limit=1&page_token=animal%2Bvideos%3B4fcb0f981d70459a9693472d6d05d7b7
User Roles Permissions
The user account permissions that exist in Backlot are also enforced in the APIs. There are five user roles:
- Administrator: Able to invoke all API calls.
- Manager: Able to invoke all API calls.
- Upload Only: Able to create assets (POST), but can only view and modify assets that the user has created. Able to view but not modify labels. Does not have access to any other APIs.
- Analytics Only: Able to access the Analytics API only.
- Read Only: Can view but not modify all assets, labels, and analytics data. Does not have access to any other APIs.
Rate Limiting
Each request made to the Ooyala APIs costs a certain number of API credits. Your credits reset every minute.
All API requests cost 1 credit unless otherwise specified.
If you do not have enough credits to make an API request you will receive a 429
response.
Each request made to our APIs, successful or not, will return the following headers:
X-RateLimit-Credits # The number of credits you have remaining.
X-RateLimit-Reset # The number of seconds until your credits reset.
View Remaining Credits and Reset Time
[GET] /v2/remaining_credits_and_reset_time
Sample response:
{
"remaining_credits": 60, // number of credits you have left
"remaining_reset_time": 0 // number of seconds you have to wait for the next reset
}
Tips to Avoid Rate Limiting
If you find yourself continually hitting the limit, you can try the following to decrease your API usage:
- Instead of making a request every time you need some information, try caching responses locally and only make requests when you expect that information to change.
- Keep an eye on your remaining credits, and if you are low try backing off the number of requests you are making until they reset.
- You may have some API users who you would like to prioritize over others. If so, you can let only your high priority API users make requests when you are low on credits.
Using Ooyala's High-Performance Cached API
In addition to our standard API, Ooyala also offers a high-performance caching layer for API calls. This caching layer may not be necessary for all applications, but it is ideal for the following cases:
- Your application generates a large number of API calls.
- There are a number of duplicate API calls, e.g. each user of your application is generating the same query against a label.
If both of these cases reflect your API usage, we encourage you to use the high-performance API and consult with your account manager regarding best practices.
Here is what you need to know to start using the high-performance API:
- API calls need to be made to http://cdn-api.ooyala.com instead of http://api.ooyala.com. You can use either HTTPS (preferred) or HTTP.
- With Ooyala's caching layer in place, a copy of your response will be cached for a few minutes. However, the expires parameter in your API queries needs to be made "cache friendly." The most important change to make is to ensure that your expires parameter does not change between every single request you make. Instead, you'll find better performance setting it to a fixed time further out in the future.
For example, you can set the expiration to always be the start of tomorrow using the following snippet (in Ruby for example):today = Date.today expires = Time.mktime(today.year, today.month, today.day) + 86400
- If you're generating URLs to be used directly from an embedded Flash or IOS application, you can simply pre-generate a url with an expires time years into the future.
Caveats: Although the API is high-performance, it is not necessarily the best solution in all cases. Caching responses in the CDN is ideal for repeated, non-unique requests. However, if you're generating unique requests (e.g., based on a user's search terms) each and every time, you'll want to make requests to api.ooyala.com directly. Additionally, in scenarios where you always need the most up-to-date response and cannot wait a few minutes for a stale, cached response to be refreshed, you should not use the high-performance cached API.
Making API Calls from Webpages Using JSONP
Ooyala's APIs support JSONP, which is used to avoid cross-domain restrictions when invoking API calls from webpages. To enable JSONP, specify the name of your javascript callback function by using the callback query string parameter:
GET /v2/labels?callback=my_javascript_function
You'll see that the response is of the form
my_javascript_function({ "items": [ ... ] })
instead of the usual JSON format:
{ "items": [ ... ]}
The function my_javascript_function
will be called with the API's response if this API call is made from a webpage's <script>
tag.
Note that JSONP is only available when using the high performance cached API, which uses cdn-api.ooyala.com
instead of api.ooyala.com
for performance reasons.