REST best practices: should a store also return metadata? - api

I'm building my first REST API (at least trying) for a personal project.
In this project there are resources called players which hold can be in a team. According to REST API design rulebook a resource should be made either to be a document or a store and one should keeps these roles as segregated as possible.
Yet I would like to append some metadata to the team resource, eg the date the team was founded. Is it okay then for GET /teams/atlanta to return this metadata (making it a document) alongside the list of players in the team (making it a store).
Is this a good idea? If so why? If not why not and how to solve this better?
I know there are no rules to developing a REST API, but there are good practices and I would like to adhere to those. Please also not that this is really my first REST API so pardon my ignorance if there is any.

I would recommend having GET /teams/atlanta return just the information about the team, such as the founding date that you mention, and then having GET /teams/atlanta/players return the list of players for that team. These distinctions become more important when you are presenting an API that uses HTTP methods other than GET.
For example, if you wanted to add a player to a team - this would be a lot easier if you could just POST a player object to /teams/atlanta/players than if you had to PUT the whole team object to /teams/atlanta every time you wanted to add one individual player.
If your API only allows retrieval of data, and if it is for a specific client application, there is an argument for combining all the team data into one object to save the client having to make additional requests for the data, but bear in mind that it is less flexible.
Your application may want to display a list of teams by calling GET /teams but you probably wouldn't want all of the player information included in each object in the list as this is quite a lot of data, but if GET /teams/atlanta returns player information then it would be inconsistent not to include it in the list version too.
I would personally favour splitting up the resources as I've suggested, and live with the fact the client may need to make an extra request or two.

Related

API - do I need the parent resource?

A person can have many reviews. My endpoint to CREATE a new review is:
post /person/{id}/reviews
How about the endpoint to UPDATE a review? I see two options:
Stick to the parent resource: patch /person/{person_id}/reviews/{id}
Only have reviews in the URI: patch /reviews/{id}
I could be sold on using either of them:
It's consistent with the previously defined endpoint, but {person_id} is not needed.
It's 'efficient' as we're not specifying a parameter ({person_id}) that is not really needed. However, it breaks the API convention.
Which one is preferable and why?
The client shouldn't have to know about ids at all. After a client creates the review, the response should include the URI to the new review like this:
HTTP/1.1 201 Created
Location: /person/4/reviews/5
The client now has the full URL to the review, making it completely irrelevant how it looks like and what information is here.
Don't forget that the URL itself is a system to create globally unique IDs, that embed not just it's own unique identity but also information on how to access the data. If you introduce a separate 'id' and 'person_id' field you are not taking advantage of how the web is supposed to work.
In terms of API design, without knowing too much detail about OP's situation I'd walk along these guideposts:
Only have reviews in the URI: patch /reviews/{id}
It's 'efficient' as we're not specifying a parameter ({person_id})
that is not really needed. However, it breaks the API convention
The "efficiency" allows for a more flexible design. There's no existing API convention broken at this point. Moreover, this approach gives you the flexibility to avoid the need of always needing the parent resource ID whenever you display your items.
Stick to the parent resource: patch /person/{person_id}/reviews/{id}
It's consistent with the previously defined endpoint, but {person_id}
is not needed.
The consistency aspect here can be neglected. It's not beneficial to design endpoints similarly to other endpoints just because the previous ones were designed in a certain way.
The key when deciding one way or the other is the intent you communicate and the following restrictions that are put on the endpoint.
The crucial question here is:
Can the reviews ever exist on their own or will they always have a parent person?
If you don't know for sure, go for the more flexible design: PATCH /reviews/{id}
If you do know for sure that it always will be bound to a particular person and never can have a null value for person_id in the database, then you could embed it right into your endpoint design with: PATCH /person/{person_id}/reviews/{id}
By the way, the same is true for other endpoints, like the creation endpoint POST /person/{person_id}/reviews/{id}. Having an endpoint like this removes the flexibility of creating reviews without a person, which may be desirable or not.

REST API design aggregate

We are creating api on employee manage app. So there is schedule in interface, where we have to show all shifts in table, for every user per row. Farther, there is summary for every user (per row) and day (per column). Should we create one big aggregate call like:
GET /api/locations/{id}/shedule
which will return all employees, shifts, summaries etc. Or maybe should we smash that to several collections like:
GET /api/locations/{id}/shifts
GET /api/locations/{id}/events
GET /api/locations/{id}/summary
GET /api/employee/{id}/summary?date_from={date_from}&date_from={date_to}
For me, second option is more flexible and there is no reason to create new abstract resource, which is shedule. In my opinion it is clearly part of interface layer and should not affect on API design.
On the other hand the big aggregate is more optimal, becouse there will be less database calls and it's easy to cache.
How do you think? Is there any source, kind of article, which can I rely on?
There's nothing RESTful or unRESTful about either approach. The semantics of URIs is irrelevant to REST. What really matters is how the clients obtain the URIs. If they are looking up URI patterns in documentation and filling up values instead of using links, the API is not RESTful.
With that in mind, I'd say the approach that is more consistent with your business and your ecosystem of applications is the best one. Don't be afraid to create aggregate resources if you feel the need to.

Should an API assign and return a reference number for newly created resources?

I am building a RESTful API where users may create resources on my server using post requests, and later reference them via get requests, etc. One thing I've had trouble deciding on is what IDs the clients should have. I know that there are many ways to do what I'm trying to accomplish, but I'd like to go with a design which follows industry conventions and best design practices.
Should my API decide on the ID for each newly created resource (it would most likely be the primary key for the resource assigned by the database)? Or should I allow users to assign their own reference numbers to their resources?
If I do assign a reference number to each new resource, how should this be returned to the client? The API has some endpoints which allow for bulk item creation, so I would need to list out all of the newly created resources on every response?
I'm conflicted because allowing the user to specify their own IDs is obviously a can of worms - I'd need to verify each ID hasn't been taken, makes database queries a lot weirder as I'd be joining on reference# and userID rather than foreign key. On the other hand, if I assign IDs to each resource it requires clients to have to build some type of response parser and forces them to follow my imposed conventions.
Why not do both? Let the user create there reference and you create your own uid. If the users have to login then you can use there reference and userid unique key. I would also give the uid created back if not needed the client could ignore it.
It wasn't practical (for me) to develop both of the above methods into my application, so I took a leap of faith and allowed the user to choose their own IDs. I quickly found that this complicated development so much that it would have added weeks to my development time, and resulted in much more complex and slow DB queries. So, early on in the project I went back and made it so that I just assign IDs for all created resources.
Life is simple now.
Other popular APIs that I looked at, such as the Instagram API, also assign IDs to certain created resources, which is especially important if you have millions of users who can interact with each-other's resources.

Various collections of resources in a CRUD REST API

I am curious as to how a CRUD REST API would implement the idea of a tweets resource. Of course, an application such as Twitter has the notion of tweet objects, but these are needed by the application in various ways ("collections").
Twitter would need an endpoint for user timeline (tweets published by a certain user) and also for the home timeline (the timeline of tweets from people a user is following). I imagine, in a CRUD API, user timeline would be located at a URI such as: tweets?filter={username:"Bob"}
However, I'm not quite sure how a CRUD API design would implement the home timeline collection of tweets. Furthermore, collections such as favourites for a user — are these treated as separate resources altogether, or should they somehow be attached to the tweets resource?
Furthermore, Twitter have not used the CRUD design for their API. Maybe there is a good reason for this?
The good thing about resource design is that it doesn't really matter, as long as it makes (some) sense. Obviously some nuances are in place, but let's get to the point. Business models don't (have to) map 1:1 to resources, this is probably why you don't find such relation in the Twitter API.
Some assumptions: Timelines are pre-defined and their behaviour isn't influenceable, other by creating new tweets. Favorites are (references to) tweets. Favorites are influenceable.
A favorite collection resource, could be something like:
/user/bob/favorites
Your "CRUD" operations could be something like:
[POST] /user/bob/favorite { "tweet_id": "343fe4a" } -- Add a new favorite
[GET] /user/bob/favorite -- All favorites, for the user Bob
[DELETE] /user/bob/favorite/343fe4a -- Delete tweet 343fe4a as being favorite
Normally it's best to avoid multiple variables in a single resource, as this introduces a certain complexity that isn't needed. In this example, however, a favorite doesn't have it's own identifier. It instead re-uses the identifier from a tweet and it's also tightly-coupled with a user.
If a favorite does have it's own identifier, I would go about creating a resource like: /favorite/ef213e13f this could return meta-data or act as an alias (redirect) to a tweet for a HTTP GET method or a resource to "un-favorite" something (DELETE method).
This statement probably makes more sense if we don't talk about tweets, but instead about a blog with articles and comments:
/blog/article/42 -- representing an article
/blog/article/42/comments -- representing a collection to all comments for this article
/blog/comment/44571 -- representing a single comment
Depending on what you want, a couple of examples for timelines could be resources like:
/user/bob/timeline/home
/user/bob/timeline?type=home
/timeline/home?user=bob
As I mentioned earlier, it's best to avoid using multiple variables in a resource. I would probably pick option 3. The reasons being, besides the complexity of having too many variables, is that such a resource probably isn't worth caching (client-side) and no CUD actions may be done on it. Since it's most likely an aggregate resource for different entities.
A couple of closing words:
Design resources first and only then come up with a matching URL
Don't design resources 1:1 to (business-)models
Don't over think the situation from the start. Implement something and tinker with it to see possible problems in the future. Once you're happy, put it in production.
Suggestions for further reading:
HAL - http://stateless.co/hal_specification.html
Hypermedia - http://en.wikipedia.org/wiki/Hypermedia
RMM - http://martinfowler.com/articles/richardsonMaturityModel.html
Roy Fielding's blog - http://roy.gbiv.com/untangled/tag/rest

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.