iosobjective-creststateless

Asynchronous stateless API


Imagine a table view listing some recipes. Each time the user taps on a recipe a new table view is loaded listing recipe ingredients.

To get the information, I'm asynchronous calling a REST API using:

NSURLRequest *request = [NSURLRequest requestWithURL:url
                                      cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                      timeoutInterval:30];

When user taps on a recipe, a call to the API is made to get recipe ingredients. However, once in the new view (which list ingredients) and before the answer is received, the user can go back and select a new recipe.

In this case, I'll receive two answer; one for each request. The problem is I don't know to what request is this answer for and I'll refresh UI with a wrong content from a wrong answer.

I'm not sure which is the right approach in this case. I'm thinking about including in the answer each request parameter. So, if I'm, for example, using the API to search for certain term, we say "foo", I'll include the term in the answer too, for example:

Request:

http://example.com/api/search?term=foo

Answer

{
"requestType": "search",
"term": "foo",
"result" : "a foo result"
}

It looks strange to me to include each request parameter on each answer, but it is the only solution I found to create a stateless API ready to be called asynchronous.

Is there any other way of accomplishing this?

(I'm using a delegate pattern assigning an object to each request which is called when the answer is received. The problem is, in the example of recipes, that the ingredients table view is reused each time recipe ingredients are listed).


Solution

  • One possibility is to include a unique "request ID" in the request, and for the server to echo it. Then the server doesn't need to return all the request parameters, just the request ID. The client would generate a new ID for each request, possibly using something as simple as incrementing an integer.

    Another possibility is to create a "cancelable asynchronous request". When you issue the request, return an object that can be used to cancel the request. If the request is cancelled before the delegate is fired, then ensure that the delegate won't be fired. When a response comes back for a canceled request, just throw it away. For your ingredients table, before you issue a new request, you cancel any pending request (so that you have at most one uncancelled request at a time).

    One way to implement this is to build a two-stage callback. The first callback, which is managed by the infrastructure, just checks to see if the request was cancelled. If not, it goes on to call the second callback (which is actually your delegate).