I want to expose my Item resource in these ways:
GET /Item (to show all Items)
GET /Item/401 (to show only the Item with key value 401)
So far so good. Now to request only the Items that belong to Me, I can think of these possible URIs constructions:
GET /Item/Mine
GET /MyItem
GET /Item/owner=42 (where my ID is 42)
I don't like the last one because it simplifies my client programming to rely on existing authentication to figure out "My" ID. I happen to be coding on ASP.NET WebAPI, but I'm really asking about the principle and design, not the implementation.
My question: Which of the three ways to represent "My" Items is most consistent with the RESTful design concept? Is it even legitimate to ask for "My" Items as such?
If users should not be able to see items that aren't "theirs", then this is an authorization issue. Just use GET /Item, and have your authorization module strip out the items that aren't theirs.
If users can see all items, and you just want to grab the items that belong to a particular user, then you should be parameterizing the call to GET /Item. Something like GET /Item/?owner=42. In this case, the user isn't limited to asking for their items .. they can ask for the items of any owner. That buys them flexibility without costing you anything.
If you have a /User resource, you could also add an endpoint /User/{id}/Item, which
returns the same collection as /Item/?owner=
And this isn't germane, but I find that plural collections (/Items, /Users) read a lot better than singulars. YMMV.
I would use GET /Items to get all itmes.
And GET /Items?owner=42.
GET /Item/Mine is not consistent since it contradicts your way of identifying the resource ie, GET /Item/401.
GET /MyItem seems seems unnecessary since the resources you are looking for can be retrieved using the other REST url paths.
Related
My data model is like this:
User: id, email, hashed_password
Item: id, name, color
UserItem: user_id, item_id, rating
and I want to write a RESTful API to get these resources. The authentication is provided via OAuth 2 with a JWT token (that contains the logged user id).
First approach
Endpoints
The first idea for a URL structure is (the one I chose when there was still no authentication):
/items/{item_id}
/users/{user_id}
/users/{user_id}/items/{item_id}
In this case a user with id 1 could use:
GET /users/1 to get their own information;
GET /users/1/items to get their own items (with rating);
GET /items to get all items that they could add to their collection.
Analysis
I think this solution is quite clear, but also unelegant.
Good:
You can easily get other users info (if they are available to them);
1-to-1 relations between endpoints and data models.
Bad:
Longer URLs;
There is redundancy (why GET /users/1/items when in the token you already have the information about id 1?).
Second approach
Endpoints
Given that you can extract the user id from the token, the structure could as well be more simple:
/items/{item_id}
/users/{user_id}
In this case a user with id 1 could use:
GET /users/me to get their own information;
GET /items?class=owned to get their own items (with rating);
GET /items?class=all to get all items that they could add to their collection.
Analysis
This solution is a bit messy but probably more elegant.
Good:
Shorter URLs;
Less redundancy (GET /items to get your own items).
Bad:
Only model UserItem is represented (even though in this case it is probably almost meaningless to get an Item without its rating, that could be set to null if the user has not yet added it);
Not straightforward to get other users' items (maybe something like GET /items?user=3?).
Conclusions
Honestly I don't know what is the best practice in this case. I feel like there is something off about both of these. Maybe there is an hybrid approach I'm not seeing?
How would you organize a model like this?
You could look into a format like HAL. HAL gives you a way to describe specific resources (items) and allows you to create multiple collections that point to those resources.
This means that individual items could be hosted at /items/xyz, but items can be both part of the /user/a/items and /items collections.
I put a lot of work into a hypermedia client: https://github.com/badgateway/ketting . This is not just an ad though, there's alternatives but that approach of API design might we well-suited for you.
But regardless of the client you're using, systems like this can avoid the issue of retrieving the same item through multiple endpoints. A single item has a canonical url, and if the system is designed well you only have to retrieve an item once.
A collection is just a list of links to the resources (items) that belong to that collection. They point to the item, but don't 'contain it', just like a regular hyperlink.
I'm rewriting an API to be more RESTful, but I'm struggling with a design issue. I'll explain the situation first and then my question.
SITUATION:
I have two sets resources users and items. Each user has a list of item, so the resource path would like something like this:
api/v1/users/{userId}/items
Also each user has an isPrimary property, but only one user can be primary at a time. This means that if I want to get the primary user you'd do something like this:
api/v1/users?isPrimary=true
This should return a single "primary" user.
I have client of my API that wants to get the items of the primary user, but can't make two API calls (one to get the primary user and the second to get the items of the user, using the userId). Instead the client would like to make a single API call.
QUESTION:
How should I got about designing an API that fetches the items of a single user in only one API call when all the client has is the isPrimary query parameter for the user?
MY THOUGHTS:
I think I have a some options:
Option 1) api/v1/users?isPrimary=true will return the list of items along with the user data.
I don't like this one, because I have other API clients that call api/v1/users or api/v1/users?isPrimary=true to only get and parse through user data NOT item data. A user can have thousands of items, so returning those items every time would be taxing on both the client and the service.
Option 2) api/v1/users/items?isPrimary=true
I also don't like this because it's ugly and not really RESTful since there is not {userId} in the path and isPrimary isn't a property of items.
Option 3) api/v1/users?isPrimary=true&isShowingItems=true
This is like the first one, but I use another query parameter to flag whether or not to show the items belonging to the user in the response. The problem is that the query parameter is misleading because there is no isShowingItems property associated with a user.
Any help that you all could provide will be greatly appreciated. Thanks in advance.
There's no real standard solution for this, and all of your solutions are in my mind valid. So my answer will be a bit subjective.
Have you looked at HAL for your API format? HAL has a standard way to embed data from one resources into another (using _embedded) and it sounds like a pretty valid use-case for this.
The server can decide whether to embed the items based on a number of criteria, but one cheap solution might be to just add a query parameter like ?embed=items
Even if you don't use HAL, conceptually you could still copy this behavior similarly. Or maybe you only use _embedded. At least it's re-using an existing idea over building something new.
Aside from that practical solution, there is nothing in un-RESTful about exposing data at multiple endpoints. So if you created a resource like:
/v1/primary-user-with-items
Then this might be ugly and inconsistent with the rest of your API, but not inherently
'not RESTful' (sorry for the double negative).
You could include a List<User.Fieldset> parameter called fieldsets, and then include things if they are specified in fieldsets. This has the benefit that you can reuse the pattern by adding fieldsets onto any object in your API that has fields you might wish to include.
api/v1/users?isPrimary=true&fieldsets=items
Suppose there's USERS and ORDERS
for a specific user's order list
You could do
/user/3/order_list
/order/?user=3
Which one is prefered and why?
Optional parameters tend to be easier to put in the query string.
If you want to return a 404 error when the parameter value does not correspond to an existing resource then I would tend towards a path segment parameter. e.g. /customer/232 where 232 is not a valid customer id.
If however you want to return an empty list then when the parameter is not found then query string parameters. e.g. /contacts?name=dave
If a parameter affects an entire URI structure then use a path e.g. a language parameter /en/document/foo.txt versus /document/foo.txt?language=en
If unique identifiers to be in a path rather than a query parameter.
Path is friendly for search engine/browser history/ Navigation.
When I started to create an API, I was thinking about the same question.
Video from apigee. help me a lot.
In a nutshell when you decide to build an API, you should decide which entity is independent and which is only related to someone.
For example, if you have a specific endpoint for orders with create/update/delete operations, then it will be fine to use a second approach /order/?user=3.
In the other way, if orders have only one representation, depends on a user and they don't have any special interaction then you could first approach.
There is also nice article about best practice
The whole point of REST is resources. You should try and map them as closely as possible to the actual requests you're going to get. I'd definitely not call it order_list because that looks like an action (you're "listing" the orders, while GET should be enough to tell you that you're getting something)
So, first of all I think you should have /users instead of /user, Then consider it as a tree structure:
A seller (for lack of a better name) can have multiple users
A user can have multiple orders
An order can have multiple items
So, I'd go for something like:
The seller can see its users with yourdomain.com/my/users
The details of a single user can be seen with yourdomain.com/my/users/3
The orders of a single user can be seen with yourdomain.com/my/users/3/orders
The items of a single order can be seen with yourdomain.com/my/users/3/orders/5
In designing a RESTful API, the following call gives us basic information on user 123 (first name, last name, etc):
/api/users/123
We have a lot of information on users so we make additional calls to get subresources on a user like their cart:
/api/users/123/cart
For an admin page we would like to see all the cart information for all the users. A big table listing each user and some details about their cart. Obviously we don't want to make a separate API call for each user (tons of requests). How would this be done using RESTful API patterns?
/api/carts/users came to mind but then you'd in theory have 2 ways to get a specific user's cart by going /api/carts/users/123.
This is generally solved by adding a deref capability to your REST server. Assuming the response from your user looks like:
{
...
cartId: "12345",
...
}
you could add a simple dereference by passing in the query string "&deref=cart" (or however you setup your syntax.)
This still leaves the problem of making a request per user. I'd posit there are two ways to generally do this. The first would be with a multiget type of resource (see [1] for an example). The problem with this approach is you must know all of the IDs and handle paging yourself. The second (which I believe is better) is to implement an index endpoint to your user resource. Indexing allows you to query a resource (generally via a query string such as firstName=X or whatever else you want to sort on.) Then you should implement basic paging so you're not passing around massive amounts of data. There are tons of examples of paging, but the simplest would be to specify a number (count=20) a start token (since=X) and a sort order (sort=-createdAt).
These implementations allow you to then ask for all users and their carts by iterating on the index endpoint. You might find this helpful as a starting point for paging [2].
[1] - How to construct a REST API that takes an array of id's for the resources
[2] - Pagination in a REST web application
For some reason I was under the assumption that having 2 URIs to the same resource was a bad thing. In my situation /api/users/123/cart and /api/carts/users/123 would return the same data. Through more research I've learned from countless sources that it's acceptable to have multiple URIs to the same resource if it makes sense to the end user.
In my case I probably wont expose /api/carts/users/123, but I'm planning on using /api/carts/users with some query parameters to return a subset of carts in the system. Similarly, I'm going to have /api/carts/orgs to search org carts.
A really good site I found with examples and clear explanations was the REST API Tutorial. I hope this helps others with planning their API URIs.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
So me and my boss aren't agreeing here and can't find any information on it. Scenario: I want to get all the users for a certain organisation. What should the URL be?
mydomain.com/users/by/organisation/{orgId}
OR
mydomain.com/organisation/{orgId}/users
Our arguments:
Case 1: The call is expected to return "users" and therefore the "resource" (first part of the call) should relate to it.
Case 2: The organisation "owns"/"is the parent of" the user and therefore the organisation should be first.
What are your thoughts?
UPDATE:
I am not to worried about what comes after the mydomain.com/{resource}. The question relates mostly to whether the HTTP action (GET, POST, PUT, DELETE) should relate to the first resource mydomain.com/users or whether it should reflect the relationship mydomain.com/organisations/users/.
You are probably aware that REST has no strict rules, you are more or less free to implement it however you like, but here are my 2 cents
mydomain.com/users/by/organisation/{orgId}
However this sounds like a good url because it sort of tells you what it does by reading it, this is not a great idea. Normally, each url segment specifies a resource that exists or can exist.
In this case, users represents one or more resources and so does organisation, but by does not, it's probably nothing more than a word to help clarify what the API does.
The call is expected to return "users" and therefore the "resource" (first part of the call) should relate to it.
A resource is not necessarily specified in the first part of the url. It can be the 2nd, 3rd or 10th if you want
mydomain.com/organisation/{orgId}/users
This looks much better but I think there is 1 point of improvement. You should rename organisation to organisations, to match users
This
mydomain.com/organisations/{orgId}
then gets the organisation with id orgId, and
mydomain.com/organisations/{orgId}/users
gets all the users that belong to that organisation.
To further narrow it down you could do
mydomain.com/organisations/{orgId}/users/{userId}
to get one specific user belonging to one specific organisation
UPDATE: I am not to worried about what comes after the
mydomain.com/{resource}. The question relates mostly to whether the
HTTP action (GET, POST, PUT, DELETE) should relate to the first
resource mydomain.com/users or whether it should reflect the
relationship mydomain.com/organisations/users/.
To answer your update:
I already mentioned it above; A resource is not necessarily specified in the first part of the url.. If the quality of the url improves by shifting the wanted resource to the back of the url, go ahead and do so
There is a conceptual difference between what you are trying to show here. The first is a filtering of all the user resources in the system based on some criteria. The second is showing the user resources that belong to an organisation.
The second url is ok for showing users that belong to an organisation I think.
The first url is effectively filtering the users that you want to see from all users.
Using the url might be ok for the filtering, though using url querystring is also be ok. so
mydomain.com/users?organisationId={orgId}
might be preferable. The urls can still contain querystrings and be restful.
Does it really make any sense to DELETE mydomain.com/users/organisation/{orgid}? Would you expect that to delete the organisation? if not then this isn't really pointing at a resource and so you are doing a search, and should probably use querystrings.
There are other options for doing the search like making the search criteria a first class object, or using one of the other filtering techniques in this question or this question
Let me start with this: technically, it shouldn't really matter. REST states that URL's must be discoverable through links, like links in normal (HTML) web pages.
However, a consistent, self-explanatory URL-structure won't harm at all. I'd suggest a hierarchical structure in URLs:
/organisations returns a list of all organisations
/organisations/123 returns a specific organisation (#123)
/organisations/123/users returns a list of users that are associated to that organisation
etc.
An alternative would be using a query string for filtering:
/users returns a list of all users
/users?organisation=123 returns a list of users that are associated to that organisation
From this hierarchical perspective, /users/by/organisation/123 wouldn't make much sense. What would be the result of calling /users/by/organisation? Or /users/by?
mydomain.com/users/by/organisation/{orgId}
What does "by" mean? That has no relationship to anything. Try to keep random words out of the URL.
Case 1: The call is expected to return "users" and therefore the "resource" (first part of the call) should relate to it.
That is not a rule that RESTful APIs enforce or expect. It is really not that common in the industry either, and I have worked with a LOOOT of APIs. Consider it to be a folder.
/users - a list of users
/users/1 - user with an ID of 1
/users/1/organizations - the orgs that user belongs to
/organizations - a list of orgs
/organizations/1 - Organization number 1
/organizations/1/users - The users for that organization
You are look at it like a programmer, like it is SOAP or a PHP function, trying to make getUsersByOrganization($orgId) and that is not how REST works. :)
IF you have to stick to case 1 (first URI segment = return type) then do this:
/users?orgId=1
That is perfectly RESTful and it is essentially just a filter. You could even do both, but I wouldn't. It is a relationship which has no place there. I try and keep filters to things like: ?active=true
The second is better. Walking down the URI should narrow the request, either as filters or showing parent-child objects. Users belong to an organization, so it should be organization/users. But I'd get rid of the "organization" level of the URI too if possible.
mydomain.com/{orgId}/users
By REST the URI structure does matter only from human perspective. It does not matter from the perspective of the REST client, because it is following link annotated with semantics.
To answer your question, it matter what do you want to describe, relationships or users. If you want to add and remove relationships, then you have to define a relationship collection. If you want to add and remove users, then you have to define an user collection. This matters only by manipulation. By GET you can define any kind of query which returns a bunch of users...