RESTful API without ID in the URL
Asked Answered
K

4

24

I have been discussing the best way of doing this with one of my colleagues

Here's an example scenario:

I'm trying to GET all orders for a Customer with ID of 1234.

Consider the following endpoint:

/customer/orders

With a GET request, with the following header:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

With the Authorization header, our auth mechanism identifies this request as for a Customer with ID 1234 and our service returns the required orders.

He is trying to persuade me this is right, because one logged in Customer, would only ever request their orders (in this case, the orders belonging to customer 1234) - so passing the ID in the URL is unnecessary. However.... To me, that isn't RESTful (I may be wrong)

In my opinion, it should be like this:.

/customer/1234/orders

With the header (As an example)

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

With the Authorization header, we verify the user has permission to retrieve those orders... If so, return them, else, return a 401

My question is, which is the preferred method?

I can certainly see benefits of the first way, but in the interest of keeping our api RESTful, my heart says to go with the second way...

Karrikarrie answered 30/12, 2013 at 19:41 Comment(2)
What approach did you go with finally?Kerosene
ended up using the approach with the auth header. Worked wellKarrikarrie
A
13

I think the second implementation (including the customer ID) is only needed if you're going to allow customers to retrieve the order data of other customers. In other words, if customer 4321 is going to be able to see the order history of customer 1234 then sending that is absolutely necessary.

My guess is they won't be able to do that. Which means if you include that information you'll likely be ignoring it in favor of the authorization code anyway.

If that's the case, I say don't even send it.

If it makes you feel any better, LinkedIn's REST API mirrors this behavior. Any user can request the profile of any other user BUT if the id is omitted it assumes the current user is requesting their own profile. Read more here

All that being said, as long as it makes sense to you and you document it you should be fine either way.

Adorn answered 30/12, 2013 at 19:50 Comment(1)
+1 Yup nothing in REST states that an URI for a resource should include an id be stated explicitly. The URI itself can be seen as the identifier and any id's contained within it as further scoping information.Navarra
P
18

Identification of resources is a key REST constraint. Your orders and my orders are not the same resource, therefore they SHOULD (not MUST) have a different identifier.

The practical reason that you SHOULD give them a unique identifier (i.e. /customers/1234/orders) is because it will be much easier to support HTTP caching. HTTP caching intermediaries primarily use the URI as a cache key. It is possible to use other headers (like auth) as part of the cache key by using the vary header, however,the support for such mechanisms is much less reliable/widespread.

Even if today you have no plans to use HTTP caching, it is better to play safe and ensure your URIs are designed to allow this capability if you need it in the future.

When doing client side URI construction, there are some benefits to not having to include the customer ID in the URI. However, RESTful systems are supposed to provide the URIs for clients to follow by embedding those URIs in returned representations. There is no need for clients to build these URIs and therefore there is ZERO additional work for clients to use URIs with the id as using the URI without the Id. If you are prepared to swallow the hypermedia pill, then there is no advantage to not including the ID.

Pay answered 31/12, 2013 at 19:17 Comment(6)
Thanks for your answer. Would be good if you could expand on the "If you are prepared to swallow the hypermedia pill" comment if possible?Karrikarrie
The hypermedia pill is adherence to the "Hypermedia as the engine" characteristic of a RESTful implementation. (wikipedia.org/wiki/HATEOAS) However, if Darrel's argument is that the client is going to blindly follow the hyperlinks responses from the server so there's no reason not to include the customer ID, one could just as easily argue the opposite - that including the customer id is unneeded because the client will be blindly following the hyperlinks. In which case I'd say why bother with standards at all?Adorn
@Adorn By having the id in the URI you using a different URI for my orders versus your orders. Hence caching can be used to with the URI as a cache key.Pay
@Adorn And there are no standards for URI design in RESTful systems. URIs should be completely opaque to the client. URI design is simply a convenience for server side routing.Pay
@DarrelMiller I understand what you're saying, but I think you're a level too deep. The resource Alex is requesting is "orders". The scope of that resource is being limited by customer id, but your customer ID does not identify the resource you're requesting (which is orders). Therefore the RESTful requirement of resource identification is neither violated nor observed in this use case.Adorn
@Adorn You are overthinking the notion of resource. A unique URI identifies a resource. "orders" is not a resource, neither is "customer". "example.org/customer/1234/orders" identifies a resource and "example.org/customer/5678/orders" identifies a different resource. The notion of resource is closer to object instance than it is to class.Pay
A
13

I think the second implementation (including the customer ID) is only needed if you're going to allow customers to retrieve the order data of other customers. In other words, if customer 4321 is going to be able to see the order history of customer 1234 then sending that is absolutely necessary.

My guess is they won't be able to do that. Which means if you include that information you'll likely be ignoring it in favor of the authorization code anyway.

If that's the case, I say don't even send it.

If it makes you feel any better, LinkedIn's REST API mirrors this behavior. Any user can request the profile of any other user BUT if the id is omitted it assumes the current user is requesting their own profile. Read more here

All that being said, as long as it makes sense to you and you document it you should be fine either way.

Adorn answered 30/12, 2013 at 19:50 Comment(1)
+1 Yup nothing in REST states that an URI for a resource should include an id be stated explicitly. The URI itself can be seen as the identifier and any id's contained within it as further scoping information.Navarra
A
8

Neither one is RESTful. The semantics of the URI should be irrelevant to a client in a RESTful application.

REST is an architectural style based on the web itself. Think about it. When you go to Stack Overflow, the only URI you're concerned about is stackoverflow.com. Once you are logged in, you're redirected to your home page, and the URI of your home page is irrelevant. Right now I have at my menu bar a link that goes to my home page, you have an identical link that goes to your home page, and we don't care what the URI is when we click it, right? On our home page, we see questions and answers, and we don't care about their URIs either, only their title and description.

Now, let's reverse it. REST being is the architectural style of the web, if the web were like you think REST is, when you join stackoverflow.com, instead of having a nice link with your name pointing to your home page you'd have a text saying "Your id is 131809, please, take the URI pattern /users/(id), replace id with this number, paste it in the address bar and you'll get to your homepage", and you think, "why those idiots don't make a link for that?"

That sounds ridiculous, but that's what most people think REST is. REST APIs must be hypertext driven.

This means that instead of being concerned if a user's orders should be at /customer/(customer_id)/orders, or just /customer/orders or even /orders and rely on his credentials, forcing the client to know all these URI patterns, you should just give him a root document at your API entry point, that considers his credentials, and gives the URIs with standard titles and descriptions, just like any website does when you log in!

So, let's say you use JSON, and your API is myapi.com. That should be the only URI a client knows. When he makes a GET request to that root document, with the proper Authorization header, he should get a JSON document like:

{"orders": "http://myapi.com/customer/123456/orders"}

And obviously, he doesn't need to know what the value of "orders" is, only that it's a valid URI that will lead him to another resource containing a collection of his orders. That URI could be anything, its semantics doesn't matter. It could be your friend's suggestion:

{"orders": "http://myapi.com/orders"}

Or anything else, that could be changed anytime:

{"orders": "http://myapi.com/this/is/a/meaningless/uri"}

Of course, you should put some effort into having clear and meaningful URIs, but that doesn't make your API more or less RESTful. Where it bears on this matter, what makes your API RESTful is how your clients obtain the URIs, and if your clients are reading URI patterns in documentation and not getting them as links in other resources, your API is not RESTful. Simple as that.

Aloes answered 24/1, 2014 at 23:26 Comment(1)
The last case is more something you would expect from an OPTIONS, not a GET request.Wirewove
A
1

If you are using the id in your /customer/[id] pattern somewhere else, it would be weird and inconsistent to omit it for the orders just because you think right now that no one else will ever see them.

If the only orders a customer will ever see are their own orders, why not just use /orders? This way, at least you avoid this inconsistency.

However, I would prefer adding the id explicitly. If in the future someone from customer support wanted to review the orders, you would have to change the URL or make a new one only for this purpose. I recommend strictly separating the identification of resources from access rights condiderations.

Austinaustina answered 22/4, 2017 at 8:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.