Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RESTful API - URI Structure Advice

I have REST API URL structure similar to:

/api/contacts                 GET          Returns an array of contacts
/api/contacts/:id             GET          Returns the contact with id of :id
/api/contacts                 POST         Adds a new contact and return it with an id added
/api/contacts/:id             PUT          Updates the contact with id of :id
/api/contacts/:id             PATCH        Partially updates the contact with id of :id
/api/contacts/:id             DELETE       Deletes the contact with id of :id

My question is about:

/api/contacts/:id             GET

Suppose that in addition to fetching the contact by ID, I also want to fetch it by an unique alias.

What should be URI structure be if I want to be able to fetch contact by either ID or Alias?

like image 702
Jatinder Thind Avatar asked Sep 03 '14 06:09

Jatinder Thind


4 Answers

If you're alias's are not numeric i would suggest using the same URI structure and figuring out if it's an ID or an alias on your end. Just like Facebook does with username and user_id. facebook.com/user_id or facebook.com/username.

Another approach would be to have the client use GET /contacts with some extra GET parameters as filters to first search for a contact and then looking up the ID from that response.

Last option i think would be to use a structure like GET /contacts/alias/:alias. But this would kinda imply that alias is a subresource of contacts.

like image 107
Stromgren Avatar answered Sep 20 '22 13:09

Stromgren


The path and query part of IRIs are up to you. The path is for hierarchical data, like api/version/module/collection/item/property, the query is for non-hierarchical data, like ?display-fields="id,name,etc..." or ?search="brown teddy bear"&offset=125&count=25, etc...

What you have to keep in mind, that you are working with resources and not operations. So the IRIs are resource identifiers, like DELETE /something, and not operation identifiers, like POST /something/delete. You don't have to follow any structure by IRIs, so for example you could use simply POST /dashuif328rgfiwa. The server would understand, but it would be much harder to write a router for this kind of IRIs, that's why we use nice IRIs.

What is important that a single IRI always belongs only to a single resource. So you cannot read cat properties with GET /cats/123 and write dog properties with PUT /cats/123. What ppl usually don't understand, that a single resource can have multiple IRIs, so for example /cats/123, /cats/name:kitty, /users/123/cats/kitty, cats/123?fields="id,name", etc... can belong to the same resource. Or if you want to give an IRI to a thing (the living cat, not the document which describes it), then you can use /cats/123#thing or /users/123#kitty, etc... You usually do that in RDF documents.

What should be URI structure be if I want to be able to fetch contact by either ID or Alias?

It can be /api/contacts/name:{name} for example /api/contacts/name:John, since it is clearly hierarchical. Or you can check if the param contains numeric or string in the /api/contacts/{param}.

You can use the query too, but I don't recommend that. For example the following IRI can have 2 separate meanings: /api/contacts?name="John". You want to list every contact with name John, or you want one exact contact. So you have to make some conventions about this kind of requests in the router of your server side application.

like image 27
inf3rno Avatar answered Sep 21 '22 13:09

inf3rno


I would consider adding a "search" resource when you are trying to resolve a resource with the alias:

GET /api/contacts/:id

and

GET /api/contacts?alias=:alias

or

GET /api/contacts/search?q=:alias
like image 30
shlomi33 Avatar answered Sep 21 '22 13:09

shlomi33


First of all, the 'ID' in the URL doesn't have to be a numerical ID generated by your database. You could use any piece of data (including the alias) in the URL, as long as its unique. Of course, if you are using numerical ID's everywhere, it is more consistent to do the same in your contacts API. But you could choose to use the aliases instead of numeric IDs (as long as they are always unique).

Another approach would be, as Stromgren suggested, to allow both numeric IDs and aliases in the URL:

/api/contacts/123
/api/contacts/foobar

But this can obviously cause problems if aliases can be numeric, because then you wouldn't have any way to differentiate between an ID and a (numeric) alias.

Last but not least, you can implement a way of filtering the complete collection, as shlomi33 already suggested. I wouldn't introduce a search resource, as that isn't really RESTful, so I'd go for the other solution instead:

/api/contacts?alias=foobar

Which should return all contacts with foobar as alias. Since the alias should be unique, this will return 1 or 0 results.

like image 37
Nic Wortel Avatar answered Sep 18 '22 13:09

Nic Wortel