Why sub resources need to be prepended with resource in URI? - api

Having a doubt on REST API URI design.
Let's consider each Post has one or more tags. So, a tag could be retrieved by
GET /posts/1/tags/1
Tags are stored uniquely in DB with an ID. So I could access full detail of a tag using
GET /tags/1
If Post information needed, then I could use query parameter
GET /tags/1?post=1
My question is why the first format widely suggested over second/third format.
Suggest me use case/scenario to prefer first format or complications with second/third format.

why the first format widely suggested over second/third format.
This is not the case. The three are used for different things.
You must first ask if a tag can exist without a post. I'd say yes. Because of this, the second form
GET /tags/1
is a good URI to get the representation of a tag.
Next, ask yourself if a post can have multiple tags. I'd again say yes. Because of this the first form is a good way to get a specific tag of a post. More general, the form
GET /posts/1/tags
returns all tags that are used for post 1. This is a collection resource. One of those tags is tag 1 which can be navigated to by
GET /posts/1/tags/1
Note that the first and the second form both identify tag 1. Both forms can be used at the same time.
The third form makes no sense at all. Query parameters after the ? like post=1 are generally used to filter a collection resource. One could say: "Give me all tags that are used on posts 1, 23, and 42. This could be formulated as
GET /tags?post=1,23,42
Here we filter the collection resource of all tags by a condition.
Your third form uses a query parameter post=1 on a single resource. But it makes no sense to filter a single tag.
A fourth form could be useful: Give me all posts that use a tag:
GET /tags/1/posts
This would return the collection resource of all posts that use tag 1.
And even a fith form with the same meaning as fourth would be possible:
GET /posts?tag=1
Summary:
When thinking about REST URIs, think about resources. What are your resource? What are the relations between them? Can one type of resource exist only "inside" another type of resource (a hotel room can only exist inside a hotel) or can it exist on its own (a tag can exist even if not post is tagged with it). What could be a subresource of another resource? What collection resources exist? How can they be filtered?

Related

REST Fetching data with GET not possible due to exceed header size limit

I am having a dilema. I need to fetch data for some products by Id, these products which are selected can vary from a couple to thousands.
I see and tested that GET is not possible due to exceeding the HeaderSizeLimit of 8192.
I had discussions with colleagues and changed to POST and the ids are in the body. Everything works but have a lot of discussions about this. Have you encountered something like this? What was your approach?
First question for me is, do you really pass all those ids in a single request? How is this list of IDs generated in the first place? Could the server know this list in advance?
For example, if the list of IDs is obtained by doing a search query on the same server, perhaps that search query can already emit the list of entities.
I find that in most cases this can be avoided, but there's some exceptions.
If you find that you can't avoid this, I would suggest you use the new http QUERY method instead of of POST, but POST should be fine too as a fallback.

REST API Resource Granularity

I wanted to get opinion on resource granularity. Say, I have a an domain entity called "magazines". But there are different types of magazines, including Sports, Nature, Automobiles, Computers and Aeroplanes, etc.
When I want to create a new "sports" magazine, should I be using construct such as:
PUT /magazines
PUT /sports-magazines
PUT /magazines/sports
When I want to get a specific sports magazine, should I be saying:
GET /magazines/{id}
GET /sports-magazines/{id}
GET /magazines/sports/{id}
If I want to get sports magazines for the year 2001, should I be using:
GET /magazines?type=sports&year=2001
GET /sports-magazines?year=2001
GET /magazines/sports?year=2001
And finally, if I want to return how many pages each type of magazine has for January 2001 publication, how would I do that? Do I need to create a new pages resource for that? Or make two independent requests or something else? First of these is listed below:
GET /magazines/pages?type1=sports&type2=nature&year=2001&month=01
GET /sports-magazines/pages?type=nature&year=2001&month=01
Given these scenarios how would you model your resources?
I have a an domain entity called "magazines". But there are different types of magazines, including Sports, Nature, Automobiles, Computers and Aeroplanes, etc.
Important thing to understand: resources aren't domain entities. Your resource model is a facade that sits in front of your domain model.
Notice, for example, that this resource (REST API Resource Granularity) describes not only your question, but also my answer.
PUT probably is NOT what you want for "create a new resource" unless the client is already in position to know what URI should be used for the new resource. The target URI of a PUT request is the same URI that we expect to use later to GET the data
PUT /magazines/{id}
GET /magazines/{id}
In the case where we don't expect the client to know what the URI is going to be... well, we don't have an HTTP method that means precisely that, so we fall back to using POST (see Fielding, 2009).
POST /magazines
201 Created
Location: /magazines/12345
Note that the machines don't care if the URI of the created resource(s) match the target URI of the POST request.
REST really doesn't care what spelling conventions you use for your resource identifiers (in much the same way that the machines don't care what spelling conventions you use for variable names).
GET /magazines?type=sports&year=2001
GET /sports-magazines?year=2001
GET /magazines/sports?year=2001
GET /magazines/sports/year=2001
GET /magazines/sports/2001
Those are all fine; there are trade-offs. Key value pairs encoded into a query string make creating URI with HTML forms easier, using path segments makes relative resolution easier.
I want to return how many pages each type of magazine has for January 2001 publication
Creating a new URI with that information is fine. Extending the schema of your existing resources to include that information is also fine.

Providing complex filtering REST API [duplicate]

This question already has answers here:
REST and complex search queries
(5 answers)
Closed 10 years ago.
So I am building a RESTful (as RESTful as I can) API with the Laravel 4 PHP Framework. Right now I have dozens of API calls working and I have a process for being to do limit, ordering, and do simple filtering. Here would be an example of one of the calls:
/api/v1/users?limit=10&offset=10&firstName=John&order[]=createdTimestamp desc
This would return the 11th through 20th users that have a first name of John ordered by the createdTimestamp in descending order. The simple filtering here can only does exact matches (=). Now I also want to be able to provide a more complex filtering system through the REST API that supports the ability to specific the equality match type that way they could do a != or > or LIKE, etc... The issue is that I don't know if I am going to be able to provide this type of filtering through a normal query string.
What is the best way to provide this complex filtering through a REST API? Is doing through a POST still considered the best way even though it is not "truly" RESTful (even though this would prevent issues of the user trying to run a long query that exceeds the URI character length limit that some browsers have)?
#ryanzec
Now I also want to be able to provide a more complex filtering system
through the REST API that supports the ability to specific the
equality match type that way they could do a != or > or LIKE, etc...
The issue is that I don't know if I am going to be able to provide
this type of filtering through a normal query string.
It's not possible with simple query string(well, maybe it's possible but is very hard to encode such logic properly in query string). You need to define custom query format and use POST to submit such query. Server may respond with:
"201 Created" status and "Location" header field indicating query resource if there was no such query before; or
"303 See Other" and "Location" header field indicating already existing query resource.
Is doing through a POST still considered the best way even though it
is not "truly" RESTful
I do not know who said this, but it's wrong. There is nothing wrong with using POST for such purposes.
Use forms in your collection resource responses to tell the client how to search the collections. See my answer to REST and complex search queries for examples.

How return the total entries in our JSON API if we use pagination by Link Header

I start implement a REST API. I have a request doing on a resource with multiple entries. To implement the pagination, I do like Github choose implement it.
I define a HTTP Header Link where I add the next/previous/first/last link.
Link: <https://api.github.com/repos?page=3&per_page=100>; rel="next",
<https://api.github.com/repos?page=50&per_page=100>; rel="last"
In my body there are only my entries and nothing else. But Now I want know how entries there are in total. I can't do a multiplication between number of page and per_page entries, because the result is not exact.
So how can I do to return this number to entries ? I think add a new HTTP Header in my answer X-total-entries. But I don't know if there are better technique or not.
When I try to decide whether to put some data into the headers or into the body, I ask myself if it is a feature of the application or of the protocol? In your case, is the pagination a feature of the application? Is the user aware what page he is looking at? Is the total number of items displayed to the user? If the answer is yes, then I would put the information into the body. Then the body becomes not just a list of items, but a representation of a page, with all the information and controls needed to display it. Only if the pagination is a internal protocol detail would I consider putting the links and the item count into the header. I know this may sound a rather abstract way of thinking, but if the pagination details need to bubble up all the way to the top of the application, there is little real benefit in separating this information from the body and putting it into the headers.

The REST-way to check/uncheck like/unlike favorite/unfavorite a resource

Currently I am developing an API and within that API I want the signed in users to be able to like/unlike or favorite/unfavorite two resources.
My "Like" model (it's a Ruby on Rails 3 application) is polymorphic and belongs to two different resources:
/api/v1/resource-a/:id/likes
and
/api/v1/resource-a/:resource_a_id/resource-b/:id/likes
The thing is: I am in doubt what way to choose to make my resources as RESTful as possible. I already tried the next two ways to implement like/unlike structure in my URL's:
Case A: (like/unlike being the member of the "resource")
PUT /api/v1/resource/:id/like maps to Api::V1::ResourceController#like
PUT /api/v1/resource/:id/unlike maps to Api::V1::ResourceController#unlike
and case B: ("likes" is a resource on it's own)
POST /api/v1/resource/:id/likes maps to Api::V1::LikesController#create
DELETE /api/v1/resource/:id/likes maps to Api::V1::LikesController#destroy
In both cases I already have a user session, so I don't have to mention the id of the corresponding "like"-record when deleting/"unliking".
I would like to know how you guys have implemented such cases!
Update April 15th, 2011: With "session" I mean HTTP Basic Authentication header being sent with each request and providing encrypted username:password combination.
I think the fact that you're maintaining application state on the server (user session that contains the user id) is one of the problems here. It's making this a lot more difficult than it needs to be and it's breaking a REST's statelessness constraint.
In Case A, you've given URIs to operations, which again is not RESTful. URIs identify resources and state transitions should be performed using a uniform interface that is common to all resources. I think Case B is a lot better in this respect.
So, with these two things in mind, I'd propose something like:
PUT /api/v1/resource/:id/likes/:userid
DELETE /api/v1/resource/:id/likes/:userid
We also have the added benefit that a user can only register one 'Like' (they can repeat that 'Like' as many times as they like, and since the PUT is idempotent it has the same result no matter how many times it's performed). DELETE is also idempotent, so if an 'Unlike' operation is repeated many times for some reason then the system remains in a consistent state. Of course you can implement POST in this way, but if we use PUT and DELETE we can see that the rules associated with these verbs seem to fit our use-case really well.
I can also imagine another useful request:
GET /api/v1/resource/:id/likes/:userid
That would return details of a 'Like', such as the date it was made or the ordinal (i.e. 'This was the 50th like!').
case B is better, and here have a good sample from GitHub API.
Star a repo
PUT /user/starred/:owner/:repo
Unstar a repo
DELETE /user/starred/:owner/:repo
You are in effect defining a "like" resource, a fact that a user resource likes some other resource in your system. So in REST, you'll need to pick a resource name scheme that uniquely identifies this fact. I'd suggest (using songs as the example):
/like/user/{user-id}/song/{song-id}
Then PUT establishes a liking, and DELETE removes it. GET of course finds out if someone likes a particular song. And you could define GET /like/user/{user-id} to see a list of the songs a particular user likes, and GET /like/song/{song-id} to see a list of the users who like a particular song.
If you assume the user name is established by the existing session, as #joelittlejohn points out, and is not part of the like resource name, then you're violating REST's statelessness constraint and you lose some very important advantages. For instance, a user can only get their own likes, not their friends' likes. Also, it breaks HTTP caching, because one user's likes are indistinguishable from another's.