For the site I am working on, we are in the process of improving our URLs for one type of resource - specifically, moving away from numerical IDs toward unique, descriptive strings. A similar example would be switching from identifying users by numerical database ID to identifying them by username (not our specific case, but analagous). So a URL to access a user's information used to look like:
/users/48573
And now it looks like
/users/thisisausername.
The only problem is that we still need to be able to fetch them through numerical IDs somehow, for legacy consumers of the API. We don't need the REST URLs themselves to redirect (e.g. /users/48573
should not redirect to /users/thisisausername
), we just need a method to obtain the right data using the old identifier. The solution should either provide an alternate way of accessing the user information (which conveniently includes the new identifier, username) by ID, or of accessing just the username by ID. Some possible solutions might be:
- Using a node to specify some alternate method of identification, e.g.
/users/byid/48573
- Using a query parameter to specify some alternate method of identification, e.g.
/users/48573?fetchby=id
or/users/48573?byid=true
- Treating username-by-id as another resource, e.g.
/identifiers/username/48573
Which of these (if any) is closest to proper REST? How would you deal with the problem?
Your first option is probably the best.
Searching for users by ID:
Searching for users by short name:
If they leave out that path parameter, you could always default to your new short username format.
Another option that I have seen quite a bit is to use query parameters like the following:
I think the first looks a bit cleaner and more readable.
Your API is not RESTful if this is an issue. To quote Roy Fielding:
Quite an old question but I had the same and finnaly found the solution : use regex in your path param.
Here's how I coded that use case
I think adding a path segment/prefix is the best answer. Since these are unique secondary keys, this isn't the same as search (which returns a set of items), so using query parameters (which aren't cached) doesn't seem like the best choice.
Personally, I plan to use a path segment prefix delimited by "=", like "name=" or "email=":
This is functionally equivalent to adding a path segment (e.g. "user/name/john.doe"), but feels to me like it maps more closely to the conceptual model. Of course, this is an insignificant detail, since RESTful APIs shouldn't specify a fixed URI structure anyway.
Not using query parameters also allows sub-resources to be accessed naturally:
Frameworks like Java's JAX-RS support using whatever delimiter you want:
I'd consider qualifying the string with an optional suffix:
If you receive a string without the suffix:
then you check the string and see if it's an ID or Name.
If you only get a valid ID but not a name then it's a retrieval by ID equivalent to:
If you only get a name back then it's a retrieval by Name equivalent to:
If you can retrieve the value by ID or Name then you return a 300 response error and return links to both possiblities to the client:
The legacy consumers continue to work 'as is' except for the occasional occurence of duplicate ID/name pairs where they receive the new 300 response error.