Contents
In the previous article in this series, I showed you how to access a Netflix subscriber's account information. In that article, I provided a sample application that enabled you to explore a Netflix subscriber's account information. One of the resources that you may have visited with the explorer is the subscriber's movie queue, representing a list of DVDs that the subscriber has assembled for rental viewing. This article will demonstrate one aspect of managing a subscriber's account information by showing you how to add, move, and delete titles from a subscriber's movie queue.
This article will show you how to:
- Obtain and use the movie titles in a subscriber's queue
- Add, delete, and move titles around in the subscriber's queue
The first step in managing a subscriber's movie queue is to obtain the queue list. Again, you may have found this list through the use of the Account Explorer example application from the previous article. The resource location is:
http://api.netflix.com/user/{user_identity}/queues/disk
Where {user_identity} is the identifier for a subscriber that you received in an account access authorization response. The subscriber queue information is obtained by submitting a protected request for this resource.
The XML document returned in the response for a queue information request is a queue
object that contains, among other things, a collection of queue_item
objects. It may not be a surprise that the contents of a queue_item
object are very similar to a catalog_title
object that is returned in a title search (as described in the second article in this series). The only difference between the two is that the queue_item
object contains additional information about the title as it relates to the subscriber's queue: position in the queue, title availability, when the item was last updated in the queue, and so on. To make a long story short, the following code shows the changes that were made to the CatalogTitle
data container class in the NetflixParser module to accommodate the additional data contained in the queue_item
objects.
public class CatalogTitle
{
public int rank;
public int position;
public string category;
public DateTime availability;
public DateTime updated;
public string idUrl;
public string ID;
public TitleName title;
public BoxArt cover;
public string year;
public string runtime;
public string avg_rating;
public List<Category> categories;
public Dictionary<string, Link> links;
public string synopsis;
public Dictionary<string, Link> cast;
public Dictionary<string, Link> directors;
}
Additional changes were made to the parser code to handle the new elements contained in the queue_item
objects. One particular change of note is the category
item. The original catalog_title
objects contain category objects that only have attributes associated with them. However, there is a category object in the queue_item
that contains both attributes and a value. There is only one such object in the queue_item
object and so its value is stored in a discrete data item, as shown in the above code snippet.
Two new parser interfaces were written to support parsing the subscriber queue information:
- ParseQueueItems parses the entire contents of the XML document returned by a request for the subscriber's queue information. This returns a list of
queue_item
objects, represented as the (now extended) CatalogTitle data objects, and the value of the etag
element that represents the queue state - I'll elaborate more on this when we get to the queue update discussion. - QueueItemInfo parses an individual
queue_item
object.
I won't go into the details of the changes to the parsing functions because these should be quite obvious in the code. An addition to the NetflixParser module is two helper functions:
- StripHtml was incorporated from the title catalog explorer application.
- ConvertTimestap was added to convert the UNIX timestamp format that Netflix uses into a .NET DateTime object.
As with a number of aspects of the Netflix documentation, and the primary reason why I've written this series of articles, I found the Netflix description of how to submit change request quite lacking in specifics. According to the Netflix API documentation, they support four HTTP methods, which correspond to the four basic data storage functions:
HTTP Method | Equivalent Operation |
POST | Create |
GET | Read |
PUT | Update |
DELETE | Delete |
I have found, however, that the HTTP PUT
method does not seem to be supported quite as expected, even though it is referenced in a few places in the Netflix API documentation. It turns out that which HTTP method should be used for a given operation is not necessarily intuitive, as will be demonstrated when I explain why moving a title in a queue uses a POST
rather than a PUT
further along in this article. Also, as a point of interest, there is an alternate way of using the POST
method to perform a delete operation. This is described shortly when I go into the implementation details.
Up until now, all of the Netflix service request have been queries, using the default HTTP GET
method. To use other HTTP methods for service requests, the following changes were made to the NetflixRequest
class:
- Two new overloaded protected requests were added that allow for the specification of the HTTP method. Like the existing pairs of request methods, one of these returns an XML string and the other returns an
XmlDocument
object. - The common function for creating the Protected service requests was modified to accept the HTTP method. The HTTP method is a required parameter for constructing a signed request signature.
- A new pair of common service request overloads were created, one using a default HTTP
GET
method and the other allowing for the specification of the HTTP method.
These changes were not required for the Non-Authorized and Signed requests, which will only ever use the GET
method.
Note: The Netflix API documentation does indicate that there may be cases where a request can exceed the nominal 256 character limit imposed by a GET
method. While this claim has been debunked as a myth, Netflix does support using the POST
method in requests where you would normally use the GET
.
You may recall that I mentioned earlier that the ParseQueueItems
method in the NetflixParser
class returns, in addition to a list of titles in the subscriber's queue, an element called the etag
. This element contains an opaque value that represents a synchronization state of the data that you have received from Netflix. The purpose of this tag is for concurrency control, that is to say to verify that the database has not changed between the time you received a set of information and the time you submitted a request to modify it. The content of this element has meaning only to the Netflix service, hence it is considered opaque. If you submit a request with a missing, or out of date, etag
you will receive an error response indicating that you must synchronize with the database. Therefore, all update requests must include a valid etag
in the query string parameters.
In this article, the example used is making changes to a subscriber's DVD queue. For this purpose, the following bit of example code demonstrates preparing a NetflixRequest
object for a Protected service request, setting the target endpoint to the subscriber's DVD queue, and adding the etag
parameter to the request.
NetflixRequest request = new NetflixRequest(txtKey.Text, txtSecret.Text,
_auth.Token, _auth.Secret);
string requestUrl = "http://api.netflix.com/users/" + _auth.UserID + "/queues/disc";
request.AddQueryParameter("etag", _etag);
Adding a title to the subscriber's queue requires only two items of information: the title identifier and, optionally, the position at which to insert the title in the queue. If the position is not specified, then the title is added to the end of the subscriber's queue. I have already covered the mechanics of searching for a title and obtaining its identity in the Netflix Catalog Explorer example in the second article in this series, so I won't go into that again here. The code snippet below shows an example of adding these two parameters to a request that will add the movie "Casper" to a subscriber's queue at position 13.
NetflixRequest request = new NetflixRequest(txtKey.Text, txtSecret.Text,
_auth.Token, _auth.Secret);
string requestUrl = "http://api.netflix.com/users/" + _auth.UserID + "/queues/disc";
request.AddQueryParameter("etag", _etag);
request.AddQueryParameter("title_ref",
"http://api.netflix.com/catalog/titles/movies/60030118");
request.AddQueryParameter("position", "13");
XmlDocument xDoc = request.ProtectedRequestXml(requestUrl, "POST");
Moving a title in the subscriber's queue is virtually identical to adding a new title, with the exception that the title already exists in the subscriber's queue. One difference is that if you wish to move the title to the end of the queue, you must place it there explicitly, rather than not including the position parameter in the request as in the Add request. The following code snippet shows an example of setting the parameters for moving a title to the end of the subscriber's queue, where lvQueue
is the ListView
control used in the example code accompanying this article.
NetflixRequest request = new NetflixRequest(txtKey.Text, txtSecret.Text,
_auth.Token, _auth.Secret);
string requestUrl = "http://api.netflix.com/users/" + _auth.UserID + "/queues/disc";
request.AddQueryParameter("etag", _etag);
request.AddQueryParameter("title_ref",
"http://api.netflix.com/catalog/titles/movies/60030118");
request.AddQueryParameter("position",
lvQueue.Items.Count.ToString());
XmlDocument xDoc = request.ProtectedRequestXml(requestUrl, "MOVE");
Note: The position value must be 1 or greater, and if not specified the title will be added to the end of the subscriber's queue.
As previously noted, although it would seem that the proper HTTP method for adding a title is "PUT
", the service rejects this action in this context. The Netflix support team explains this by stating that moving a title in a queue actually creates the title entry in the queue at a new location, which consequently overrides its previous position because there can be only one instance of a title in a given queue.
In order to differentiate a title creation from a movement, I added a pseudo-method of "MOVE
". This differentiation is required in order to provide the proper behavior when the new queue position, which is optional, is not provided. See the source code for the implementation details.
Lastly, deleting a title from the subscriber's queue is slightly different from the previous two operations, but still quite simple. In this case, the URI for the title to be removed from the queue must point specifically to the available titles queue. In addition, the HTTP DELETE
method is specified for the Protected request. The following code snippet illustrates the parameters required for removing a title from the subscriber's movie queue:
NetflixRequest request = new NetflixRequest(txtKey.Text, txtSecret.Text,
_auth.Token, _auth.Secret);
string requestUrl = "http://api.netflix.com/users/" + _auth.UserID + "/queues/disc";
requestUrl += "/available/" + title.ID;
request.AddQueryParameter("etag", _etag);
XmlDocument xDoc = request.ProtectedRequestXml(requestUrl, "DELETE");
Note that in this example, the HTTP request method is specified as DELETE
. An alternative that the Netflix API allows is to specify the HTTP POST
method and also adding a method
query parameter set to delete
, as shown in the following equivalent example:
NetflixRequest request = new NetflixRequest(txtKey.Text, txtSecret.Text,
_auth.Token, _auth.Secret);
string requestUrl = "http://api.netflix.com/users/" + _auth.UserID + "/queues/disc";
requestUrl += "/available/" + title.ID;
request.AddQueryParameter("etag", _etag);
request.AddQueryParameter("method", "delete");
XmlDocument xDoc = request.ProtectedRequestXml(requestUrl, "POST");
The stated reason for this alternative is for testing purposes using a Web browser, in which you might not be able to specify the HTTP request method. Another possible reason, although not specifically stated in the documentation, may be that not all HTTP code libraries might support the full set of HTTP methods, whereas you can always count on support for GET
and POST
.
One of the things you might notice in this example application is that I have relocated all of the Netflix supporting modules into a NetflixAPI
namespace. I did this as a first step towards consolidating all of this code into a self contained library module, which, I'm sorry to say, is beyond the scope of these articles. But at least I've given you a hint for where you might take my code examples from here.
Throughout this entire series, I have used the most simple means of performing synchronous HTTP service requests. A change you might consider, if you choose to build on the example code I've provided, is to make the calls asynchronous so that the user is not subjected to the annoying application wait cursor while the request is pending completion. Be sure to read my comments about this in the conclusion of this article.
The program requires the account access authorization tokens that were the subject of the previous article. For the sake of simplicity, I have not included the code for obtaining these tokens in this example. Instead, you must copy the accessInfo.xml token container file that was created by the Netflix Account Explorer example application to where this article's example program is executing.
After passing the account access authorization check, you enter your Netflix developer consumer key and secret and then click Q, which loads the ListView
control with the titles in the subscriber's queue of available titles.
Note: The example code has set the max_results
option in the service request to 100 (the maximum allowed by the Netflix API), overriding the default value of 25. You might consider retrieving the information in the subscriber's queue in smaller chunks, or you will have to if the number of items in the subscriber's queue exceeds 100. You do this by utilizing the number_of_results
value returned in the response to determine the total number of chunks needed, and the start_index
option in conjunction with the max_results
option the request to retrieve selected chunks of data. This technique may be also be employed to provide progress information to the user of the application where very large blocks of data are being requested, and also reduces the impact to the application operation should a request fail.
After the subscriber's queue titles are loaded, right-clicking on any item in the list pops up a context menu that allows you to choose from three options - add a new title to the queue, move an existing title from one position in the queue to another, or remove an item from the queue.
When Add is selected from the context menu, a dialog form is launched that allows you to search for a title to add to the queue. You may recognize this form as the main application form from the Catalog Explorer application in Part II of this series. You simply type a title, or partial title, to search for and click Search to obtain a set of search results.
Note that in the previous screenshot the Add button is disabled. It remains disabled until a title has been selected from the results list, as shown in the next illustration:
The application notes the position in the queue where the mouse cursor was located when the right-click that brought up the context menu occurred and uses this as the default insertion location for the new title. This form also provides the option of inserting the title at either the top or the end of the subscriber's queue. Clicking Add returns the information to the main application where the queue update operation is executed.
When Move is selected from the context menu, a dialog form is launched that allows you to change the position of a title in the queue. As in the Add operation, the location of the mouse cursor in the queue list is captured and displayed as the current and new queue positions for the selected title.
The NumericUpDown
control is used to set the new location for the title in the queue, and there are also options to simply move the title to the top or the end of the queue. The following illustration shows an example of moving the selected title to the beginning of the subscriber's queue.
Clicking OK returns the information to the main application where the queue update operation is executed.
Removing a title from the queue is much easier than the previous operations. All that is required is a simple MessageBox prompt that allows the user to confirm or reject the delete action.
Clicking Yes returns the confirmation to the main application where the queue update operation is executed.
This article has described and demonstrated how to access the titles in a subscriber's queue, and how to manage the entries in that queue. This is only one of the features of a subscriber account that you can manipulate with the Netflix APIs. The documentation gives you all the details about the damage, er... I mean clever things, you can do to a subscriber's account with updates.
This is the last article in this series and I hope they have been helpful. I hope that this has given you a good start and that you are beginning to think of some ideas for a great Netflix application of your own now that you understand the basics. As I ride off into the sunset, I will leave you with a few final pointers that you might keep in mind as you write your own Netflix applications.
- As I've mentioned several times in these articles, the code examples use synchronous HTTP requests. In simple terms, this means the application waits until the request (and response) has completed before continuing execution. Now you might consider running these requests in another thread or using asynchronous requests in order to download bulk data. However, you should be aware that Netflix limits client applications to no more than four requests per second.
- Speaking of limits, you should also keep in mind the following limits:
- Signed requests are limited to 5,000 per day.
- Protected requests are limited to 5,000 per day, per subscriber account.
- The maximum number of results you can request using the
max_results
parameter is 100. If you are dealing with large amounts of data, you need to request it in chunks, using the start_index
parameter.
- I've taken the liberty to call all of my example applications "Netflix"-something-or-other. It is strictly forbidden to use "Netflix" as the first word in an application name. You should read the Netflix Branding Requirements for guidelines before choosing a name for your application.
- September 5, 2009
- September 8, 2009
- February 25, 2010
- Corrected reversed functionality of
PUT
and POST
actions in the HTTP Method
table - Provided additional clarification about the
POST
action when used for moving titles in the queue