Resource Versioning - Using ETags

ETags are useful to developers in a number of circumstances. First, developers can use ETags to perform conditional retrieval to avoid retrieving a resource or collection which hasn't changed since the last time it was retrieved. Second, developers should use ETags to avoid collisions between operations which change the data provided by the service: update and delete operations.

Conditional Retrieval

If you want to retrieve an entry that you've retrieved before, you can improve efficiency by telling the server to send the entry only if it has changed since the last time you retrieved it.

To do this sort of conditional retrieval, send an HTTP GET request that includes an HTTP If-None-Match header. In the header, specify the entry's ETag.

If-None-Match: W/"D08FQn8-eil7ImA9WxZbFEw."

When the server receives this request, it checks to see whether the entry that you requested has the same ETag as the ETag you specified.

  • If the ETags match, then the entry hasn't changed, and the server returns an HTTP 304 Not Modified status code.
  • If the ETags don't match, then the entry has been modified since the last time you requested it, and the server returns the entry.

Updating Entries

The easiest way to avoid overwriting another client's changes is for the server to make sure that when your client sends an updated entry, the version of the entry that your client started with is the same as the current version stored by the server. If a second client makes an update before your client does, then your client's update is denied, because your client is no longer basing its modifications on the latest version.

When your client retrieves data from a service that supports strong ETags, each entry has an ETag that acts as a unique version identifier for that version of that entry.

Updating using ETags works only with strong ETags.

For services that supply weak ETags, all updates succeed, regardless of whether someone else has updated the entry since you retrieved it; the newest update always overwrites any other prior updates. So don't send weak ETags when updating or deleting; you'll get an error message if you do.

So when your client sends an update to a strong ETags service, it needs to specify what version of the entry it's updating. There are two ways to do that:

ETag Preferred Specification Order

  1. Use an If-Match HTTP header.
  2. Use the gd:etag attribute in the Atom <entry> element.

We recommend the If-Match Header approach where possible.

If-Match Approach

To update an entry using If-Match:

  1. Start by acquiring the entry you're updating.
  2. Make any desired changes to the entry.
  3. Create a new PUT request containing the modified entry.
  4. Before sending the PUT, add an HTTP If-Match header containing the ETag from the original entry.
  5. Send the PUT request.
If-Match: "S0wCTlpIIip7ImA0X0QI"

Server Responses:

  • Update succeeds - server returns an HTTP 200 OK status code, and a copy of the updated entry.
  • Update fails - if the update fails because the ETag you specified doesn't match the current ETag on the entry (which implies that the entry has changed on the server since you last retrieved it), then the server returns an HTTP 412 Precondition Failed status code.
  • Update fails - if you fail to provide an ETag, and the server is requiring an ETag, then the request should fail and the server returns an HTTP 409 Conflict status code.

Atom Feed/Entry "gd:etag" Attribute Approach

If you can't easily write HTTP headers, or have some other reason to avoid using the If-Match header, then you can use the gd:etag attribute instead.

If you don't send an If-Match header, then the server uses the updated entry's gd:etag attribute value as an implied If-Match value. The same server responses above can then be applied.

Deleting Entries

Deleting entries using strong ETags works much like updating them.

To delete an entry that has a strong ETag:

  1. Retrieve the entry you want to delete.
  2. Before sending the DELETE, add an HTTP If-Match header containing the ETag from the original entry.
  3. Send a DELETE request to the entry's edit URL.

If you want to make sure that you don't delete an entry that has been changed by another client since you retrieved it, then include an HTTP If-Match header that contains the original entry's ETag value.

If an entry does not have a strong ETag, then a DELETE request always succeeds.