To Verb or Not To Verb - that is the question (today)...

198 views
Skip to first unread message

Richard Berger

unread,
Apr 9, 2012, 3:43:56 PM4/9/12
to API Craft
After watching the HATEOAS video today, I realized I had a question
about implementing an actual finite state machine through REST. The
general situation is that my objects - consider them SuperTasks - can
be in one of several states and the user takes an action that moves
the SuperTask from one state to another.

It seems that the standard solution to this is to update the state
through a Put.

BUT, in my case it seems that I wouldn't want the client developer to
know all the possible states of the finite state machine, but I think
the developer would be more comfortable dealing with the user actions
(agree to SuperTask, complete it, reject it, renegotiate, cancel).
This would lead to an api similar to /supertask/id/action=agree (the
evil verb approach :) ).

Is there an obvious approach to this - or is either approach equally
valid? Note: I was assuming that when the client app does a Get on
the SuperTask, I would provide the available actions that could be
taken at that state, so the client wouldn't have to generate them.
But the question is still which flavor update-put or verb to use.

Thanks much!
RB

Mike Schinkel

unread,
Apr 9, 2012, 4:33:33 PM4/9/12
to api-...@googlegroups.com
On Apr 9, 2012, at 3:43 PM, Richard Berger wrote:
It seems that the standard solution to this is to update the state
through a Put.

BUT, in my case it seems that I wouldn't want the client developer to
know all the possible states of the finite state machine, but I think
the developer would be more comfortable dealing with the user actions
(agree to SuperTask, complete it, reject it, renegotiate, cancel).
This would lead to an api similar to /supertask/id/action=agree (the
evil verb approach :) ).

What about this?

PUT /supertask/id/status

<body>: agree

-Mike

Mike Kelly

unread,
Apr 9, 2012, 5:43:31 PM4/9/12
to api-...@googlegroups.com
You might also want to require an If-Match header to prevent
conflicts, and possibly have the client explicitly specify the
identity of the user that is agreeing to the supertask.

Cheers,
Mike

Daniel Roop

unread,
Apr 10, 2012, 5:51:36 PM4/10/12
to api-...@googlegroups.com
I think it is ok for link "rel"s to be verbs "approve", "decline" etc...

I think some people are starting to accept that some verbs in URLs are ok.  The trend I have seen is calling them Controller Resources, or Action Resources.  Both REST In Practice and the REST API Design Rule Book talk about them if I remember correctly.

I tend to think about verbs as a bad smell and a habit that needs to be broken, but once you have broken it and understand the difference between a resource and a method some uses are appropriate.

The other way to tackle this is to provide a collection that represents the actions you want to do....

For instance imagine you had an invitation that could be approved or declined.

You could have

/invitations/<id>
/invitations/<id>/accept
/invitations/<id>/decline

Or you could have

/invitations/<id>/
/accepted-invitations/
/declined-invitations/

Where to the bottom two collections you post the URL or ID of the invitation to perform the state transition.  The way I rationalize this, is imaging you are filling out a form with the acceptance, and that collection keeps track of those forms for you.

Another thing to consider is that if you are using links, either one of these should work, because your link relation should define the method that should be used, as well as the content that should be sent.  If you are using something WRML or at least the link "rel" resource it suggest the client can discover atl east the method in the rel resource.

Daniel Roop

Richard Berger

unread,
Apr 10, 2012, 6:47:07 PM4/10/12
to API Craft
Thank you to everyone for taking the time to provide some guidance. I
am now much more comfortable going with a "PUT" with a URL something
like /invitations/<id>/accept, /invitations/<id>/decline, etc. (Mike
S - I would consider putting the actName inside the body, but that
would require a bit more learning on my part).

Also the suggestion of If-Match header to make sure that the act is
still valid is very helpful (but sadly, requires yet more learning).
I am planning to add OAuth for user verification - but that is in the
future.

Again, thanks to all, I am set for now.
RB

Greg Brail

unread,
Apr 10, 2012, 8:24:06 PM4/10/12
to api-...@googlegroups.com
What about the "action" pattern that I've seen on a few APIs, combined with POST, like this:

GET /invitations/{id} : Read the invite
POST /invitations/{id}?action=accept : Accept it
POST /invitations/{id}?action=decline : Decline it
DELETE /invitations/{id} : Rescind the invitation (only authorized for the organizer)
PUT /invitations/{id} : Update it (add a dial-in number, directions, etc).

With this pattern, "/invitations/{id}" unambiguously refers to a single invite, which you can manipulate using the standard verbs or not as you extend your API. The POST with the "action" parameter is essentially a partial update of the invite, with semantics that depend on the action. (Yes, it's like a method call, so shoot me ;-)

You could also use PATCH for that if you wanted to be fancy.
--
Gregory Brail  |  Technology  |  Apigee

landlessness

unread,
Apr 10, 2012, 8:38:05 PM4/10/12
to api-...@googlegroups.com
+1 what Greg wrote.

i often model resources as state machines and include event & state params.

PATCH /invitations/{id}?event=accept
Accept it (using PATCH to be fancy)

GET /invitations/{id}
Read the invite. It will have attribute 'state' with value 'accepted'

when i build stuff with Rails, i use the state_machine gem with most of my models to support this behavior: https://github.com/pluginaweek/state_machine

-b

Richard Berger

unread,
Apr 13, 2012, 1:08:12 AM4/13/12
to API Craft
The action/event approach would work well in my model - so I will
shift gears and go with that.

This situation reminds me of my earliest days as a programmer (back
when IBM was inventing punch cards :)  ) - I would often be facing
"six of one/half-dozen of the other" type decisions.  So I would ask
one senior person who would convince me to go with the "6 of one" and
then two days later I would talk to another senior person who would
convince me that clearly "half dozen of the other" was the way to go.
 If this happens to anyone out there enough so that you feel like a
ping-pong ball - you can follow what I did - I went into
management :) :).

Thanks all!
RB

Matthew Bishop

unread,
Apr 14, 2012, 11:38:31 AM4/14/12
to API Craft
I like this approach, but I would avoid the query params. Query
params, while enticing, really shouldn't be used to communicate
resource state or transitions. You could accomplish this same thing
like this:

PUT /invitations/{id}
{ "accept" : true }

Generally speaking, PUT should be used to update an existing resource;
it's existing because it has an ID.

To create the invitation you would POST to the invitations resource:

POST /invitations
{ "name": "Picnic", "date" : "..." }

The response would be:
201 CREATED
Location: /invitations/ID



On Apr 10, 5:24 pm, Greg Brail <g...@apigee.com> wrote:
> What about the "action" pattern that I've seen on a few APIs, combined with
> POST, like this:
>
> GET /invitations/{id} : Read the invite
> POST /invitations/{id}?action=accept : Accept it
> POST /invitations/{id}?action=decline : Decline it
> DELETE /invitations/{id} : Rescind the invitation (only authorized for the
> organizer)
> PUT /invitations/{id} : Update it (add a dial-in number, directions, etc).
>
> With this pattern, "/invitations/{id}" unambiguously refers to a single
> invite, which you can manipulate using the standard verbs or not as you
> extend your API. The POST with the "action" parameter is essentially a
> partial update of the invite, with semantics that depend on the action.
> (Yes, it's like a method call, so shoot me ;-)
>
> You could also use PATCH for that if you wanted to be fancy.
>

Jurgens du Toit

unread,
Apr 26, 2012, 4:07:42 AM4/26/12
to api-...@googlegroups.com
+1 PUT'ing an updated attribute to the resource.

At the end of the day, any action can be defined as a change to a property of a resource. The beauty of REST (at least for me) is that it forces you to think in this way.

Some properties will be more abstract than others, so you will need to map the updating of a property to a specific action on the backend:

For a login action, instead of doing users/?action=login, do

PUT /user_sessions
{ username: myun, password: somepw }

Logout will be

PUT /user_sessions
{ logged_in: false }

It helps if you stop trying to map resources directly to your data sources, as you will be trying to run functions on those objects. REST breaks when you try to do that.

J


--
Jurgens du Toit
Cell: +27 83 511 7932
Website: http://jrgns.net

If people never did silly things, nothing intelligent would ever get done.
  - Ludwig Wittgenstein

Richard Berger

unread,
Apr 26, 2012, 12:20:54 PM4/26/12
to API Craft
Interestingly people seem to be about equally split between the two
general options (Verb vs. Put). For my specific situation I have
implemented the "verb" and thus far it seems to be going fine
(although the Put would certainly work too). As Jurgens mentioned -
it is a good issue to think through.

Thanks all,
RB
Reply all
Reply to author
Forward
0 new messages