I wonder what saying good practices create REST API. Should or not I create URI which will allow get e.g. several specific users?
For example I mean:
/usermanagement/users/{j_goldman,wafik,morder}
And this uri will be returns 3 objects users for j_goldman, wafik and morder.
You can do this but it won't be restful IMHO. If you really need to do this you should think about remodeling your resource selections say, all three users you want to get belong to a particular group with id 111. Then you can do something like /groups/111 GET. If you cannot then I guess you should stick with restful solution and use three API calls to get users separately.
What you are doing is searching for a specific set of users. With a query parameter within your URL, you can achieve this.
To return a single user (id is 5):
/usermanagement/users/5
To return all users:
/usermanagement/users
To return a set of users based on search:
/usermanagement/users?username=
That way, your API is open to searching by a specified criteria which can also be extended.
Say, you wish to search by location:
/usermanagement/users?location=
Say, you wish to combine these:
/usermanagement/users?username={criteria}&location={criteria}
You may also want to expose a search endpoint itself:
/usermanagement/search
You might find other options here too:
RESTful URL design for search
Related
Let's take the following resource in my REST API:
GET `http://api/v1/user/users/{id}`
In normal circumstances I would use this like so:
GET `http://api/v1/user/users/aabc`
Where aabc is the user id.
There are times, however, when I have had to design my REST API in a way that some extra information is passed with the ID. For example:
GET `http://api/v1/user/users/customer:1`
Where customer:1 denotes I am using an id from the customer domain to lookup the user and that id is 1.
I now have a scenario where the identifier is more than one key (a composite key). For example:
GET `http://api/v1/user/users/customer:1;type:agent`
My question: in the above URL, what should I use as the separator between customer:1 and type:agent?
According to https://www.ietf.org/rfc/rfc3986.txt I believe that the semi-colon is not allowed.
You should either:
Use parameters:
GET http://api/v1/user/users?customer=1
Or use a new URL:
GET http://api/v1/user/users/customer/1
But use Standards like this
("Paths tend to be cached, parameters tend to not be, as a general rule.")
Instead of trying to create a general structure for accessing records via multiple keys at once, I would suggest trying to think of this on more of a case-by-case basis.
To take your example, one way to interpret it is that you have multiple customers, and those customers each may have multiple user accounts. A natural hierarchy for this would be:
/customer/x/user/y
Often an elegant decision like this can be made, that not only solves the problem but also documents your data-model in a way that someone can easily see that users belong to customers via a 1-to-many relationship.
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.
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.