I am creating a WCF webservice with WcF Authentication Service and the first set of functions I need is to manage an inbox for a client. The client will be determined by the authentication.
This is my attempt at a RESTful design of the API:
https://api.mydomain.com/v1/inbox/messages (GET)
Returns a page of results in the inbox with an optional search filter applied
- Count - number of records per page
- Page - page to start on
- Sort - (optional) field to sort on
- Search - (optional) text to search for
https://api.mydomain.com/v1/inbox/mark (POST)
Marks one or more messages read or unread
- Action - MarkRead or MarkUnread
- MessageIDs - list of Message IDs to mark
https://api.mydomain.com/v1/inbox/archive (POST)
Archives one or more messages
- MessageIDs - list of Message IDs to archive
Am I doing this right? If 开发者_C百科not, what would be a better way to design this interface?
Martin Fowler has a good summary of the Richardson Maturity Model and what it takes to make a RESTful service. Jan referenced one of Roy Fielding's posts, but there are some steps to take care of in addition to hypermedia (and HATEOAS).
With reference to the Richardson model, I think your API would need some changes to get to "Level 3" (duh duh duhhhh). The /v1/inbox/messages
collection looks sound, and only supporting GET
indicates that it's a read-only resource to the user. However POST
ing actions and IDs to the /v1/inbox/mark
and /v1/inbox/archive
is only tunneling RPC-style services over HTTP - "Level 0" in the article.
I'd suggest something like the following as being a naive, non-hypermedia (i.e. "Level 2") API:
To retrieve a list of summary information of all of the messages (in all folders):
GET /v1/messages HTTP/1.1 Host: api.mydomain.com
Response:
content-type: text/xml <?xml version="1.0"?> <messages> <message subject="Subject" unread="true" id="1234" folder="inbox" /> <message subject="Hello, world" unread="false" id="24" folder="inbox" /> ... </messages>
To retrieve a full message:
GET /v1/messages/1234 HTTP/1.1 Host: api.mydomain.com
Response:
content-type: text/xml <?xml version="1.0"?> <message subject="Subject" unread="true" id="1234" folder="inbox"> Hi, this is the message. </message>
To edit a message (e.g. to mark it as read and move it to the archive folder):
POST /v1/inbox/messages/1234 HTTP/1.1 Host: api.mydomain.com content-type: text/xml <?xml version="1.0"?> <message id="1234" unread="false" folder="archive" />
Note: here I'm intentionally using
POST
instead ofPUT
to indicate a partial update.
Other things that stand out as needing attention are:
Hypermedia responses and media types. Frankly this is better explained by others (e.g. the REST In Practice book, or the InfoQ Coffee Cup example by the same authors), but in short your responses should indicate to the client what other actions might be possible from the response to their most recent request, and allow them to discover the entire API from just a single URI. As an example, there is an implication of folders collections above. If
GET /v1/messages/1234
returned:<message subject="Subject" unread="true" id="1234" folder="inbox" > Message text here. <link rel="folder" href="http://api.mydomain.com/v1/folders/inbox" /> </message>
then the client would have a concrete example of a URI to try an
OPTIONS
on, and a good idea of what might be there.Response codes and content:
200 OK
is obvious. Respond with403 Forbidden
if the user is not authorized to view a particular message,404 Not Found
if the message ID doesn't exist. Every time you return an error, give the client some indication of how to correct their request (if at all possible).
Regarding to read/unread part I do not think you need a post. I think you need put method https://api.mydomain.com/v1/inbox/messageId/Read https://api.mydomain.com/v1/inbox/messageId/Unread
Post needed when creating a new record and you want to update
For archive part I am agree. Just remember to return result for the archiving process.
Roy's POST is helpful when facing such questions: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Hence: focus on defining media type(s) instead of coupling your clients to predefined sets of URIs. They need not be registered, to be useful, BTW.
Maybe also see http://www.nordsc.com/ext/classification_of_http_based_apis.html#http-type-one
精彩评论