What are the options for handling flags and attributes in a REST API?
Let's say you have a complex resource in a REST API. You have several one-to-many flags and attributes on this resource (i.e., a user may have given the resource a rating of 1 to 5 or the user may hav开发者_JAVA百科e 'liked' the resource or marked it as spam or ignored it or caused some other state to be set).
Some suggestions have been made on the best way to represent this in a resource-centric architecture, but so far none of them have really made me happy. So let's crowd-source this; which variants do you find easiest to understand? Which variants haven't we thought of? Assume an OAuth-based API and everything here is done in the context of the currently authorized user.
Boolean Flags
Variant 1:
GET /resource/{id}/muted POST /resource/{id}/muted BODY:true POST /resource/{id}/muted BODY:false
Variant 2:
GET /resource/{id}/muted PUT /resource/{id}/muted BODY:true DELETE /resource/{id}/muted
Variant 3:
GET /resource/{id}/attributes POST /resource/{id}/attributes BODY:muted=true POST /resource/{id}/attributes BODY:muted=false
Variant 4:
GET /resource/{id}/muted POST /resource/{id}/mute POST /resource/{id}/unmute
Attributes
Variant 1
GET /resource/{id}/rating POST /resource/{id}/rating BODY:4
Variant 2:
GET /resource/{id}/rating PUT /resource/{id}/rating BODY:4 DELETE /resource/{id}/rating
Variant 3:
GET /resource/{id}/attributes POST /resource/{id}/attributes BODY:rating=4 POST /resource/{id}/attributes BODY:rating=
Thoughts? Suggestions? How have other APIs handled this? How have you handled it? Have you found that design issues like this have had significant effects on developer happiness or the ease-of-use of your APIs?
From Roy's dissertation:
a uniform interface degrades efficiency, since information is transferred in a standardized form rather than one which is specific to an application's needs. The REST interface is designed to be efficient for large-grain hypermedia data transfer
So you need a variant 5 which works for both flags and other attributes:
GET /resource/{id}/ BODY:{muted: false, like: false, rating: 2, ignored: true}
POST /resource/{id}/ BODY:{muted: true, like: false, rating: 2, ignored: true}
POST /resource/{id}/ BODY:{muted: false, like: false, rating: 2, ignored: true}
One big reason is that most of a RESTful HTTP application's efficiency comes from caching, and that works best when its artifacts are at as large a grain as possible, and when its data is reachable at as few identifiers as possible. If you expose the 'muted' flag at both /resource/{id}/
and /resource/{id}/muted
, then you have a cache invalidation problem. If you expose it only at /resource/{id}/
, then you don't.
If you are designing an application that aims for efficiency via small payloads, then you cannot benefit from large grain caching, and the REST architectural style is not appropriate for your app. HTTP probably isn't either, but I can understand how someone might be stuck with that in today's market.
I like Variant 3 if I can provide a bunch at once -- otherwise, I'm indifferent between 1 and 3.
And, definitely nothing that uses DELETE.
精彩评论