Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Am I designing this WCF RESTful interface correctly?

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 not, what would be a better way to design this interface?

like image 798
Jason Avatar asked Sep 13 '11 22:09

Jason


1 Answers

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 POSTing 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 of PUT 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 with 403 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).

like image 112
Ian Avatar answered Nov 04 '22 01:11

Ian