REST - how design an URI with composite keys?

Krock picture Krock · Dec 17, 2013 · Viewed 7.7k times · Source

I have a question about how design a resource URI with composite keys.

I have a resource called freight that has 4 keys/ids: partner ID, initial zipcode, final zipcode and weight.

Actually my resource was designed to have an incremental ID generated by database, but this approach is not so good to API consumers, for example if a consumer/partner needs to update a freight info they have to do:

GET freight?initialZipcode={VALUE}&finalZipcode={VALUE}&weight={VALUE}

The response of the operation above would be the freight ID, so finally they can update the info:

PUT freight/{ID}

The partner ID is implicit by the authentication mechanism.

For me it seems strange force the partners to obtain the freight ID before update the info.

So my question is: how can I design this URI?

PUT freight/initialZipcode/{VALUE}/finalZipCode/{VALUE}/weight/{VALUE}

Have I to consider the design above?

Another question: is a good practice to embedded the partnerId in authentication mechanism? I know the pros (easy to consumers) and cons (cache, impossibility to share an URI, etc), but I don't know if generally is a good or bad practice.

Thanks!

Answer

Darrel Miller picture Darrel Miller · Dec 17, 2013

There is nothing wrong with

PUT freight?initialZipcode={VALUE}&finalZipcode={VALUE}&weight={VALUE}

Query parameters are part of the resource identification too.

Path parameters are useful for defining resources that fit nicely in a hierarchy. In your case the resource doesn't fit well in a hierarchy, so don't try and squeeze the parameters into path segments.

The only challenge is what to do when the client re-arranges the order of the query params. Do you you treat it as the same resource, or do you 404? If you are not caching the GET responses then it probably doesn't matter.

If you provided your client with a URI template for them to fill in then there is less chance that they will give you the params in the wrong order.


The other option, if you go with your original suggestion is that your GET returns a redirect and a Location header to a URI with the freight ID. e.g.

GET freight?initialZipcode={VALUE}&finalZipcode={VALUE}&weight={VALUE}
=> 
302 See Other
Location:  freight/1232321322

By doing this, your client doesn't have to know anything about the freight ID, it can just grab the location header, and follow the redirect to do a GET, or do a PUT directly against whatever URI is in the Location header. This means that if you decide you don't like exposing the ID in the future, you can change the URI without breaking any clients.