Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it valid to modify a REST API representation based on a If-Modified-Since header?

I want to implement a "get changed values" capability in my API. For example, say I have the following REST API call:

GET /ws/school/7/student

This gets all the students in school #7. Unfortunately, this may be a lot. So, I want to modify the API to return only the student records that have been modified since a certain time. (The use case is that a nightly process runs from another system to pull all the students from my system to theirs.)

I see http://blog.mugunthkumar.com/articles/restful-api-server-doing-it-the-right-way-part-2/ recommends using the if-modified-since header and returning a representation as follows:

  • Search all the students updated since the time requested in the if-modified-since header
  • If there are any, return those students with a 200 OK
  • If there are no students returned from that query, return a 304 Not Modified

I understand what he wants to do, but this seems the wrong way to go about it. The definition of the If-Modified-Since header (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24) says:

The If-Modified-Since request-header field is used with a method to make it conditional: if the requested variant has not been modified since the time specified in this field, an entity will not be returned from the server; instead, a 304 (not modified) response will be returned without any message-body.

This seems wrong to me. We would not be returning the representation or a 304 as indicated by the RFC, but some hybrid. It seems like client side code (or worse, a web cache between server and client) might misinterpret the meaning and replace the local cached value, when it should really just be updating it.

So, two questions:

  • Is this a correct use of the header?
  • If not (and I suspect not), what is the best practice? Query string parameter?
like image 823
fool4jesus Avatar asked Oct 14 '14 14:10

fool4jesus


People also ask

What is if-modified-since HTTP header?

The If-Modified-Since request HTTP header makes the request conditional: the server sends back the requested resource, with a 200 status, only if it has been last modified after the given date.

What are the If-modified-since and if none match headers used for?

The If-Modified-Since header is used to specify the time at which the browser last received the requested resource. The If-None-Match header is used to specify the entity tag that the server issued with the requested resource when it was last received.

How HTTP protocol with if-modified-since header enables the caching in a Web browser?

When a conditional request is made for a particular resource, the client provides the server with the Last-Modified date of its cached copy by using the If-Modified-Since header. The server then determines based on these headers if the client's cached copy is the most recent version of this file.

What HTTP status code means that the requested file was found but has not changed since date provided in the IF-modified-since header?

If the status of a particular resource is 304 Not Modified, this means that the file has not changed and there is no need to download it again.


1 Answers

This is not the correct use of the header. The If-Modified-Since header is one which an HTTP client (browser or code) may optionally supply to the server when requesting a resource. If supplied the meaning is "I want resource X, but only if it's changed since time T." Its purpose is to allow client-side caching of resources.

The semantics of your proposed usage are "I want updates for collection X that happened since time T." It's a request for a subset of X. It does not seem like your motivation is to enable caching. Your client-side cached representation seemingly contains all of X, even though the typical request will only return you a small set of changes to X; that is, the response is not what you are directly caching, so the caching needs to happen in custom user logic client-side.

A query string parameter is a much more appropriate solution. Below {seq} would be something like a sequence number or timestamp.

GET /ws/schools/7/students/updates?since={seq}

Server-side I imagine you have a sequence of updates since the beginning of your system and a request of the above form would grab the first N updates that had a sequence value greater than {seq}. In this way, if a client ever got very far behind and needed to catch up, the results would be paged.

like image 177
Timothy Shields Avatar answered Dec 05 '22 00:12

Timothy Shields