I feel like I understand REST fairly well in a basic implementation of
CRUD. Where I am less confident is when we go beyond simple read/
update/delete and migrate method calls and business logic to resources
with states. Since we're not "supposed to" call something like
/my/uri/to/resource/foo/myFunctionCall
Then we need some way to trigger myFunctionCall() by way of a session-
less state change. I thought this article had an interesting point of
view:
http://blog.dhananjaynene.com/2009/06/rest-is-the-dbms-of-the-internet/
He goes to say:
"Traditional SOA based integration visualises different software
artifacts being able to interact with each other through procedures or
methods. REST effectively allows each software artifact to behave as a
set of tables, and these artifacts talk to each other using SELECT,
INSERT, UPDATE and DELETE. (or if you wish GET, PUT, POST, DELETE).
And where exactly is is the business logic ? Is it in the stored
procedures ? Not Quite. Its in the triggers."
In the triggers! Interesting way of relating REST to something we're
all familiar with. Let's talk in specifics about a specific workflow,
for an event registration (a domain problem near and dear to my
heart):
Client searches for events near location
Client picks an event and gets a description of the event from server
Client puts a registration
Server saves registration (status of new)
Server sends email receipt
Server sends email notification to event organizer
Server updates cached list of attendees
Client gets list of attendees for event (which now includes Client)
Client puts an updated registration (changing a lunch preference, for
example) (status = new)
Server sends email notification to event registrar
Client gets updated registration, payment status is = balance due
Client gets available credits -> returns list of payment credits
Client puts a payment that uses one $50 credit, supplies a discount
code and credit card credentials
Server processes payment. In our system, this means something very
specific and interdependent:
- If one or more discount codes are provided, apply them to the
balance first and reduce the total due by that amount (but don't go <
0)
- If one or more payment credits are supplied, apply them to the
balance and reduce the total. If one of the credits is larger than
the balance, roll the balance forward into a new credit
- Charge the credit card for any remaining balance
- Only if the credit card payment is successful should the discount
codes and credits be saved.
- Server returns answer of success or failure, let's assume success
Server updates registration status from new -> confirmed
Server sends email receipt to Client
Server sends email notification to registrar
Client gets updated registration, status is now confirmed
I think, if I am understanding these posts correctly, that the right
approach is for everything to have a status and you can have a
resource for anything. So in the case of the above, the convo might
look like:
GET /events?zipcode=94103 -> return list of events near zip code in
json/xml
GET /events/23 -> return details of event #23
POST /registration -> based on details of #23, send data required to
register, returns link to /registration/2903423 (registration
#2903423)
GET /events/23/attendees -> return list of attendees
PUT /registration/2903423 (update lunch)
GET /registration/2903423 (payment status is balance due)
GET /member/100/credits?event=23 (get all available credits that can
be used for #23, returns a $50 credit with id 5000)
POST /registration/2903423/payment (include credit id 5000, discount
code "CHEAP" and credit card details modeled in a json/xml packet) ->
returns success
GET /registration/2903423 -> representation is now in confirmed
status, all is done.
If we model things in the trigger model, it seems like my REST api
needs to look at an incoming resource and compare the current and
proposed state and generate actions based on that. Implementation-
wise, does this requires everything to have a status/state flag?
This doesn't sound a lot different than an event-based MVC framework
like Model-Glue, etc where the resources is the "event" and the
actions that are subsequently called on the Controller for
ValidationRegistration, SaveRegistration, SendEmailNotification, etc.
But what about when it's less of a resource and more of an action,
"search" for example? This guy would suggest you simply convert your
verb to a noun and have at it:
http://blog.dhananjaynene.com/2008/11/rest-fomenting-unrest-is-restfulness-a-semantics-game-why-does-rest-require-statelessness/
My question is - is this how people are doing it? If not, how are you
handling state changes that require additional actions? I'm
struggling with how to convert the minimal service-juggling logic
currently found in my Controllers into a stateless REST API (well, and
statelessness in general) The logic above is just one example but
concrete enough to hopefully have a practical discussion.
I would love to see notes from anyone who has created a REST api from
an application and how you modeled your resources and representations
compared to your Objects and methods.
Brian