RE: Re: How to compromise when designing a RESTful API?

2006-09-17 Thread Winters, Chris
 Thanks John for the great feedback. 
 
  On the source account, you'd initiate a transfer with the arguments 
  being the target account and the amount.  The result on 
 success would 
  be that specific transfer's ID.
 
 Ah, but you're not saying how you 'initiate a transfer'. It's 
 one of the questions I'm struggling with. It  could be:
 ...
 POST /transfer/account/123
 Host: myserver.com
 Content-Length: XXX
toAccount456/toAccount
amount300/amount 
 
 The problem I  have with the first approach is that I'm still 
 passing an action, i.e. doing some kind of RPC. My 
 understanding is that in a 'pure' RESTful API the only way to 
 specify the action is via the HTTP method (get,post,put,delete).
  The second solution seems even worse as it mixes the action 
 with the resource.

It *seems* like you're passing an action, but IMO what you're actually
doing is turning the action into a resource, which is very powerful.
That resource has a unique address, a state that can be transferred, and
is only manipulated with our four magic verbs. You can even make it
asynchronous by posting a transaction and polling for its status later
at the resource's URL.

There was actually a useful post about this sort of approach on
rest-discuss a couple days ago:

http://tech.groups.yahoo.com/group/rest-discuss/message/6561
 
 And what if I want to close all accounts that have been 
 inactive for at least a year, without retrieving them one by one?
 Would this approach: 
 
 POST /account/?inactivityPeriod=365
 Host: myserver.com
 Content-Length: XXX
actionclose/action
 
 be more appropriate than this one?
 POST /account/
 Host: myserver.com
 Content-Length: XXX
actioncloseInactive/action
   inactivityPeriod365/inactivityPeriod

If you don't want to retrieve them one by one I think you can do the
same thing, invert an action into a resource with something like:

  GET /accounts/?inactivityPeriod=365

You get back a set of account URLs:

  accounts
 account link=/account/1234 /
 account link=/account/1235 /
 account link=/account/1236 /
  /accounts

Which maybe you can POST to an 'account closing' resource:

  
  POST /account-closer
  accounts
 account link=/account/1234 /
 account link=/account/1235 /
 account link=/account/1236 /
  /accounts
  
  201 Created
  Location: /account-transaction/2006-09-18-A

   
  GET /account-transaction/2006-09-18-A
  
  200 OK
  transaction status=Closed
  resources
  account link=/account/1234 /
  account link=/account/1235 /
  account link=/account/1236 /
  /resources
  /transaction

Since that's a separate resource, you can ask questions of it, like find
the most recent transactions:  

  GET /account-transaction/recent

Or whatever. I'm pretty sure this isn't gospel, but it makes sense to
me, and I think demonstrates the power of the 'resource' abstraction.
 
Chris


Re: Re: How to compromise when designing a RESTful API?

2006-09-17 Thread Vincent

 
I think the approach you're advocating forces the client to know way more about
the server than it should, and to make it do way more work than it has to.


  POST /transfer/account/123
  Host: myserver.com
  Content-Length: XXX
 toAccount456/toAccount
 amount300/amount 
  
 
 It *seems* like you're passing an action, but IMO what you're actually
 doing is turning the action into a resource, which is very powerful.
 That resource has a unique address, a state that can be transferred, and
 is only manipulated with our four magic verbs. You can even make it
 asynchronous by posting a transaction and polling for its status later
 at the resource's URL.

 http://tech.groups.yahoo.com/group/rest-discuss/message/6561

So, you're suggesting that  a URL like /transferMoney/account/123 is indeed a
resource, especially if it is used in conjunction with a transaction (as
Benjamin suggested in his post):
client - server: POST /transferMoney
server - client: created; location: http://myserver.com/transferMoney/789
client - server: PUT   /transferMoney/789
  fromAccount123/fromAccount
  toAccount456/toAccount
  amount300/amount

The fact that the transfer happens inside a transaction is a server concern; the
client does not need to have this knowledge. Plus, it forces the client to make
2 calls instead of one.

 
  And what if I want to close all accounts that have been 
  inactive for at least a year, without retrieving them one by one?
  Would this approach: 
  
 
 If you don't want to retrieve them one by one I think you can do the
 same thing, invert an action into a resource with something like:
 
   GET /accounts/?inactivityPeriod=365
 
 You get back a set of account URLs:
 
   accounts
  account link=/account/1234 /
  account link=/account/1235 /
  account link=/account/1236 /
   /accounts
 
 Which maybe you can POST to an 'account closing' resource:
 
   
   POST /account-closer
   accounts
  account link=/account/1234 /
  account link=/account/1235 /
  account link=/account/1236 /
   /accounts


Here are the issues I see with this approach:
 - you force the server to expose an extra search API 
 - the result set could be huge. 
 - increased traffic between the client and the server
 - you still have a RPC-sounding resource (the accountCloser)
 

 Or whatever. I'm pretty sure this isn't gospel, but it makes sense to
 me, and I think demonstrates the power of the 'resource' abstraction.

H, it seems to me that you're bending to API to make it fit the REST model,
to the point where you end up breaking the abstraction layers (client knows/does
too much). 
I'm a REST newbie, so I might very well change my mind and adopt your point of
view, but -at this point- I'm still unconvinced by this 'action as a resource'
approach.

-Vincent.