The REST-way to check/uncheck like/unlike favorite/unfavorite a resource - ruby-on-rails-3

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.

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: handling nested resources and paths

I have three resources, owner, dog, and puppy and I am designing the REST endpoints for the puppy. I already know who the owner is with every request via JWT authentication, so I never need to expose their ID through API paths or request bodies.
I would like a owner to be able to POST, PATCH, DELETE, GET all, or GET one on puppy when they make requests to the API. The POST (creation) of a puppy requires the ID of the dog because they have a parent-child relationship, but all of the other operations do not. In addition, I would like a owner be able to GET all of their puppies and filter this by dog if they need to.
Given these constraints, how would you design your API:
Option #1 (un-nested, passing the dog ID in the POST body)
POST /puppies
- include `dogId` in the POST body
PATCH /puppies/{puppyId}
DELETE /puppies/{puppyId}
GET (one) /puppies/{puppyId}
GET (all) /puppies
- allow for a query string of ?dog={dogId} to be passed to filter on dog
Option #2 (nested, even though it may be unnecessary for several verbs)
POST /dogs/{dogId}/puppies
- include `dogId` in the path
PATCH /dogs/{dogId}/puppies/{puppyId}
DELETE /dogs/{dogId}/puppies/{puppyId}
GET (one) /dogs/{dogId}/puppies/{puppyId}
GET (all) /dogs/{dogId}/puppies
- lose ability to get all puppies per owner
Option #3 (mix nested/un-nested wherever necessary)
POST /dogs/{dogId}/puppies
GET (all) /dogs/{dogId}/puppies
PATCH /puppies/{puppyId}
DELETE /puppies/{puppyId}
GET (one) /puppies/{puppyId}
GET (all) /puppies
- extra endpoint so we can get all puppies per owner
I like option #1 for its simplicity and conciseness, but am unsure if sending dogId in the POST body would be considered bad practice. I like #3 for its accuracy, but I think it makes finding endpoints difficult (especially in documentation) because the root resource in the path switches between puppy and dog.
First thought: Alice's list of puppies and Bob's list of puppies are different lists of information, so they should normally be treated as different resources, with different identifiers.
HTTP has different caching rules for caching responses to authorized requests and caching responses unauthorized requests, so you'll probably get away with using the same resource identifier and changing the representations. Think carefully about whether a single identifier really offers significant benefits over the "just be normal" case.
Second thought: the target uri used to change the representation of a resource should normally be the same as the target uri used to fetch the representation of the resource.
You don't have to do it this way, of course, but if you do you get standardized cache invalidation "for free". (How important is that? probably less important than it was in the 90s).
So if
GET /ABCDE
returns a document with a list of Spot's puppies, and you are trying to register a new puppy sired by Spot, then:
POST /ABCDE
Is a natural way to do that - the target uri of the edit request matches the document you are editing.
The machines don't care what design you actually use for your resource model, or what conventions you use for identifying resources, which is good, it means that you can instead choose spellings that make life easier for the human beings that you care about.
I like #3 for its accuracy, but I think it makes finding endpoints difficult
That's what hyperlinks are for. Instead of the client playing "guess the URI", or using some out of band information, you "just" share links, and let the client follow the links to navigate through the graph of resources.
(That's not to say that you should or shouldn't use style #3, only that you shouldn't compromise your URI design to address problems that already have standardized solutions.)
I would not seperate the puppies from the dogs. After a few years they become adult dogs and you'd need to move them to the dog category. I think it would be something like this:
POST /dogs
PATCH /dogs/{dogId}
DELETE /dogs/{dogId}
GET (one) /dogs/{dogId}
GET (all) /dogs
GET (puppies) /dogs?puppies=true
GET (dogs) /dogs?puppies=false
GET (parent) /dogs/{dogId}/parent
GET (owner) /dogs/{dogId}/owner
GET (dogs & puppies of the owner) /dogs?owner={ownerId}
GET (puppies of the owner) /dogs?puppies=true&owner={ownerId}
GET (dogs of the owner) /dogs?puppies=false&owner={ownerId}
As of listing the dogs of an owner you can use authorization based on your JWT. I am not sure why you think the owner id is a secret. Better to have proper cache control headers if you don't want the client to store it. You can use some sort of uuid generator if you don't want it to be guessable.

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.

Rest-style API design - merging models into one resource?

My question is about when it's OK to merge separate models into one single REST resource and whether this leads to tricky and difficult to work with design, down the line.
Let's say I have a movie streaming service and users can only watch movie genres they have permissions for. Let's say these are represented with these hypothetical models:
users (id)
movie_genres (id, genre_name)
users_to_genres_permissions (id, genre_id, user_id)
exposed through REST routes /users /movie_genres and /users_to_genres_permissions
Now, as a user client of this API (think a website or a mobile app), in order to find out what genres I'm allowed to get hold of, I would fetch the genres permissions and then all the movie genres. Two network calls.
However, an argument could be made that having to make multiple round-trips to the API is inefficient, and you additionally have to deal with a bunch of joins on the client. This example is simple enough with its 3 relations, but in the real world you could have much longer chains.
Thus one could consider collapsing two models into one, and for example return permissions already joined to movie genres:
movie_genres (id, genre_name, authorized_for_current_user)
However the question is, this thought process can be taken pretty far. You could save the client a lot of joins and round-trips by doing all joining on the server. However, at what point do you stop? At what point is what you returning no longer a REST resources but a generic blob of data that's been concatenated together?
Is there a rule of thumb for deciding where to draw the line?
REST stands for Representational State Transfer. From wiki:
Requests and responses are built around the transfer of
representations of resources. A resource can be essentially any
coherent and meaningful concept that may be addressed. A
representation of a resource is typically a document that captures
the current or intended state of a resource.
As such, RESTful web-services provide access to resources, which means, that any API call should concentrate on one resource - and that should be your "rule of thumb".
The example that you posted is very basic, but if you'll add more entities, such as: movie-producers, actors, media-companies etc, then each request should handle only one entity. That said, your backend would need to handle requests that will require it running JOINs, for example, movies recommendations for user X. But don't let it confuse you - the request should be very simple and the response should include a "list" of objects of type movie (only one entity!).

CakePHP: model-based permissions?

Struggling with a decision on how best to handle Client-level authentication with the following model hierarchy:
Client -> Store -> Product (Staff, EquipmentItem, etc.)
...where Client hasMany Stores, Store hasMany Products(hasMany Staff, hasMany EquipmentItem, etc.)
I've set up a HABTM relationship between User and Client, which is straightforward and accessible through the Auth session or a static method on the User model if necessary (see afterFind description below).
Right now, I'm waffling between evaluating the results in each model's afterFind callback, checking for relationship to Client based on the model I'm querying against the Clients that the current User is a member of. i.e. if the current model is Client, check the id; if the current model is a Store, check Store.clientid, and finally if Product, get parent Store from Item.storeid and check Store.clientid accordingly.
However, to keep in line with proper MVC, I return true or false from the afterFind, and then have to check the return from the calling action -- this is ok, but I have no way I can think of to determine if the Model->find (or Model->read, etc.) is returning false because of invalid id in the find or because of Client permissions in the afterFind; it also means I'd have to modify every action as well.
The other method I've been playing with is to evaluate the request in app_controller.beforeFilter and by breaking down the request into controller/action/id, I can then query the appropriate model(s) and eval the fields against the Auth.User.clients array to determine whether User has access to the requested Client. This seems ok, but doesn't leave me any way (afaik) to handle /controller/index -- it seems logical that the index results would reflect Client membership.
Flaws in both include a lengthy list of conditional "rules" I need to break down to determine where the current model/action/id is in the context of the client. All in all, both feel a little brittle and convoluted to me.
Is there a 3rd option I'm not looking at?
This sounds like a job for Cake ACL. It is a bit of a learning curve, but once you figure it out, this method is very powerful and flexible.
Cake's ACLs (Access Control Lists) allow you to match users to controllers down to the CRUD (Create Read Update Delete) level. Why use it?
1) The code is already there for you to use. The AuthComponent already has it built in.
2) It is powerful and integrated to allow you to control permissions every action in your site.
3) You will be able to find help from other cake developers who have already used it.
4) Once you get it setup the first time, it will be much easier and faster to implement full site permissions on any other application.
Here are a few links:
http://bakery.cakephp.org/articles/view/how-to-use-acl-in-1-2-x
http://book.cakephp.org/view/171/Access-Control-Lists
http://blog.jails.fr/cakephp/index.php?post/2007/08/15/AuthComponent-and-ACL
Or you could just google for CakePHP ACL