Natural keys and RESTful URLs
Asked Answered
I

4

11

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.

Interfluent answered 10/7, 2014 at 4:0 Comment(1)
Nice, I mean I never though of v0 in the examples but it makes sense. :-)Synthiasyntonic
E
3

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
Enmesh answered 10/7, 2014 at 16:51 Comment(0)
C
1

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.

Coverlet answered 2/9, 2014 at 13:8 Comment(0)
H
0

Here's an idea a little more robust than Mike's by using a key param to denote the natural key the resource ID refers to:

mysite.com/api/v0/sites/23

and

mysite.com/api/v0/sites/someothersite.com?key=domain-name

In your controller you can validate the key param to only be your natural keys, rather than say querying the table meta info for the unique indexes. If you don't like to pollute the query string you could also use a HTTP header.

Headcloth answered 25/9, 2016 at 17:55 Comment(0)
S
0

Be aware that ORM entities or domain entities aren't resources. There can be a mapping between these entities and the resources. The resource is an application interface concept, you can describe the interface of your service with resources and operations on these resources.

So your primary key does not identify a resource, it identifies an entity. Resources are identified by URIs. The URIs are not unique identifiers, so you can use multiple URIs to identify a single resource.

Mark is right, you can use a similar URI template

mysite.com/api/v0/sites/{id}
mysite.com/api/v0/sites/{hostname}

if your routing framework supports differentiation between routes by type. So if the type is numeric, then the id route will run, and if the type matches a hostname regex pattern, then the hostname route will run. Otherwise you can merge the 2 routes and handle the differentiation between them manually with your code.

Synthiasyntonic answered 25/9, 2016 at 19:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.