Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 902
Ivan Avatar asked Apr 14 '11 15:04

Ivan


2 Answers

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!').

like image 145
joelittlejohn Avatar answered Oct 14 '22 05:10

joelittlejohn


case B is better, and here have a good sample from GitHub API.

  1. Star a repo

    PUT /user/starred/:owner/:repo

  2. Unstar a repo

    DELETE /user/starred/:owner/:repo

like image 30
Spark.Bao Avatar answered Oct 14 '22 04:10

Spark.Bao