Question

I want to use OData and get some benefits from HTTP caching. I've settled on rule "one entity has one URI". There are many ways how to perform query to one entity, lets say Product with SKU=123 (which is PK):

/MyService.svc/Product(123)

or

/MyService.svc/Product?$filter=sku eq 123

or even

/MyService.svc/Product(123)?$filter=sku eq 123

The most obscure way how to query this product is via title:

/MyService.svc/Product?$filter=title eq 'Some handy product'

(lets expect that this query returns only one entity - Product 123)

My question is: what is the most OData-way how to respond to this kind of queries?

After some research, my last opinion is:

  • let Product(123) work as is
  • in case of $filter=sku eq 123 / id eq 123 respond with HTTP 302 and Location header pointing to Product(123).
  • in case of Product(123)?$filter=sku eq 123 to respond with 400 (Bad Request), because its silly. Or maybe with 302 redirect to Product(123)..

But what to do with the last case?

Was it helpful?

Solution

Product(123) -> You should return the single entity in your response payload

Product(123)?$filter=sku eq 123 -> That doesn't really make sense - filter is supposed to apply to collections of entities, and Product(123) identifies a single entity (always). Many OData services today ignore this due to the behavior or early server stacks, but a 400 is acceptable since the query option does not apply.

Product?$filter=sku eq 123 -> Product identifies an entity set, so a collection of entities (AKA feed) should be returned. Even though your particular query happens to identify a single entity, a feed with a single entity in it is REQUIRED response.

Product?$filter=title eq 'Some handy product' -> This is the same as sku eq 123 in terms of the expected response. Even though it might identify a single resource, this does not change the fact that an entity set must still contain a feed as a response.

You said that you wanted to hold the rule that one entity has one URL. In OData, one URL identifies an entity, though multiple URLs could give you the same information about it. So, I'd argue that you are OK. The one URL that identifies a resource is called the canonical URL. Product(123) is a canonical URL. In, say, a JSON payload, the odata.id would give the canonical URL of an entity.

So what about these other queries that SEEM to reference the same entity? In your valid filter examples (the 3rd and 4th ones), your path identifies a COLLECTION as I indicated above. The fact that the collection happens to contain just one entity is irrelevant. The path that IDENTIFIES the resource is still Product(123). Other URLs can give give information about that entity without 'identifying' it. So I don't think that you've broken you're statement in any way.

To answer the 3xx part of your question: You are always free to respond to a request with some sort of redirect - that is part of HTTP, and OData does not change that. However, to redirect to something that is not the same shape as the original request would be a bad server behavior. For instance, Product(123)?$filter=whatever identifies a Collection of Product entities. To redirect to Product(123) would be a bad idea in my opinion, since it identifies a single entity. The response that you would write out would look different! I'd be surprised if any existing OData clients could handle that, and I wouldn't expect new ones to handle it either.

What does this mean for HTTP Caching? Well, quite frankly, at least in the scenario's given, I don't think you should do anything special.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top