I have a RESTful API that I'm designing which uses numeric primary keys for all of its resources. However one type of resource has a convenient natural key, which I'd like to be able to use as an optional way to specify the individual resource. For consistencies sake all resources will be accessible via their primary key.
As it stands, I can do this (assuming 23
is the primary key):
mysite.com/api/v0/sites/23/
However, I'm wondering if there's an idiomatic way to specify an alternate natural key for a resource.
So far I was thinking of doing something like this:
mysite.com/api/v0/sites/?domain-name=someothersite.com/
So an individual site resource would be accessible by both its primary key and a natural key (its domain name). My primary concern is doing this in and idiomatic fashion, seeing as I'd like to make the API as straightforward to use as possible.
Although URLs containing parameters within the query string do themselves conform to REST constraints, the term “REST-style URL” is often used to signify a URL that contains its parameters within the URL file path, rather than the query string.
It is for these reasons that Django provides natural keys. A natural key is a tuple of values that can be used to uniquely identify an object instance without using the primary key value.
A natural key is a column or set of columns that already exist in the table (e.g. they are attributes of the entity within the data model) and uniquely identify a record in the table. Since these columns are attributes of the entity they obviously have business meaning.
A natural key (also known as business key or domain key) is a type of unique key in a database formed of attributes that exist and are used in the external world outside the database (i.e. in the business domain or domain of discourse).
In your particular situation, the primary key (integer) can always easily be differentiated from the domain name (string including a period). It seems perfectly valid (and intuitive) to allow both in the same location of the URL:
mysite.com/api/v0/sites/23
mysite.com/api/v0/sites/someothersite.com
Documenting it is straightforward too, as each is a unique identifier for a site:
mysite.com/api/v0/sites/{id}
id: primary key or fully-qualified domain name
I've also struggled with finding a satisfying answer to this question. I had already started to implement the same as Mike Dunker suggested, but eventually encountered some resources for which it is just not possible to distinguish between the surrogate key and the natural key. It was then that I realized I'd rather have a uniform approach to this instead of mixing different ways - like you say, something idiomatic.
One other approach I found is described at http://soabits.blogspot.de/2013/10/url-structures-and-hyper-media-for-web.html (under "Natural keys, surrogate keys, URL aliases and resource duplication").
The idea is to define one of the two possible key schemes as the canonical one and realize the other one by adding a segment to the URI and using a HTTP 303 (See Other) to redirect to the canonical URI.
So in your example, you could have mysite.com/api/v0/sites/23/
as the canonical ID and mysite.com/api/v0/sites/domain-name/someothersite.com/
would reply with HTTP 303 and a location header containing mysite.com/api/v0/sites/23/
(or the other way round). Using redirects for URI aliases instead of "duplicating" the same resource is useful for the reasons named at http://www.w3.org/TR/webarch/#uri-aliases.
The reason why I did not go with this solution either is the additional HTTP round trip, which may be too expensive in our project setup.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With