Response code when POSTing existing resource

966 views
Skip to first unread message

codingoutloud

unread,
Mar 25, 2012, 10:54:59 PM3/25/12
to API Craft
Consider a POST method for a free trial for a game (e.g., 15 days -
but you can't get a second trial). User's email is provided in the
POST to api.somegame.com/trial. In common case, 201 (resource created)
is returned. What makes sense for return code if user already exists
and (a) is still in trial period, or (b) trial period has ended?

Do these make sense?
For (a) - 304 (unmodified) or 200 (ok)
For (b) - 403 (forbidden) or 402 (payment required - Wikipedia says it
is reserved for future use, though cites example of Apple using it -
and actually seems a decent semantic fit)

I know I could require a GET to avoid most complexity, but since it
will still be possible to POST so I'm interested in getting semantics
right.

Thanks in advance for pointers and insights.

-Bill

mca

unread,
Mar 25, 2012, 11:04:52 PM3/25/12
to api-...@googlegroups.com
I in similar cases, I return 400 w/ a body that contains a link to the
previously created resource.

mca
http://amundsen.com/blog/
http://twitter.com@mamund
http://mamund.com/foaf.rdf#me

Duncan Cragg

unread,
Mar 26, 2012, 10:05:12 AM3/26/12
to api-...@googlegroups.com
I'm going to give what is apparently, and to me surprisingly, a controversial response within the REST community.. watch the sparks fly! 
 
What makes sense for return code if user already exists 
and (a) is still in trial period, or (b) trial period has ended? 


(a) and (b): 200 OK!

Why? Well, I believe you should clearly and cleanly separate your concerns between:
  • simple hypermedia transfer, with corresponding status codes for that - usually just 200, 301/2/4, 400/1/3/4, 500/2/4 are enough - and 
  • domain or application content-level interactions, with status declared explicitly - "state": "in-trial-period" - or implicitly - "trial-period-info": { "start": .., "end": .. }
I see your trial-period interactions as the concern of the domain or application layer - /above/ the hypermedia transfer layer!

Further, I believe that considering '402 Payment Required' (and even '409 Conflict') is a red flag that you're mixing up your layers and not separating your concerns.

This came up recently on an internal ThoughtWorks mailing list, and it got pretty heated... I'm still baffled why this is - I mean, we all agree that you have to draw the separation-of-concerns line somewhere, in that the content mostly contains stuff which HTTP simply doesn't care about.

I'm suggesting keeping the HTTP layers and code as clean as possible by only using the least amount necessary just to /transfer your hypermedia/ - status codes only refer to the success or achievement of that. Indeed, I would only use the most commonly-used parts - the parts that are tried-and-tested. That is what REST refers to as 'Self-Descriptive Messages'.

Cheers!

Duncan

PS Mike A: I read '400' as a syntax error. Which is even lower in the HTTP stack, and way below the domain level. :-)

codingoutloud

unread,
Mar 26, 2012, 11:20:17 AM3/26/12
to API Craft
Thanks mca. Your answer is similar to Dunkin's - return something more
explicit rather than finding the right HTTP status code to map to
business nuances. The 400 makes me squirm a bit, though I like
Dunkin's 200 response code suggestion.

Cheers,
-Bill

On Mar 25, 11:04 pm, mca <m...@amundsen.com> wrote:
> I in similar cases, I return 400 w/ a body that contains a link to the
> previously created resource.
>
> mcahttp://amundsen.com/blog/http://twitter.com@mamundhttp://mamund.com/foaf.rdf#me

codingoutloud

unread,
Mar 26, 2012, 11:24:29 AM3/26/12
to API Craft
[ Sorry - "Dunkin" should be "Duncan" - forgive me, I'm from Boston
(where there is a well-known brand of coffee with a similar name).
This is a sign that I need more caffeine already... ]

On Mar 26, 11:20 am, codingoutloud <codingoutl...@gmail.com> wrote:
> Thanks mca. Your answer is similar to Dunkin's - return something more
> explicit rather than finding the right HTTP status code to map to
> business nuances. The 400 makes me squirm a bit, though I like
> Dunkin's 200 response code suggestion.
>
> Cheers,
> -Bill
>
> On Mar 25, 11:04 pm, mca <m...@amundsen.com> wrote:
>
>
>
> > I in similar cases, I return 400 w/ a body that contains a link to the
> > previously created resource.
>
> > mcahttp://amundsen.com/blog/http://twitter.com@mamundhttp://mamund.com/f...

codingoutloud

unread,
Mar 26, 2012, 11:30:34 AM3/26/12
to API Craft
Duncan - thanks for this - this is sensible and clear thinking. I get
that the SoC part and life will be hopeless if we try to map all
business nuances into HTTP codes. The 200 indicates there was no
problem with the HTTP session. The rest is business domain.

Care to share some of the more compelling reasons against 200 from
your internal discussion?

Cheers,
-Bill

On Mar 26, 10:05 am, Duncan Cragg <duncan.cr...@gmail.com> wrote:
> I'm going to give what is apparently, and to me surprisingly, a
> controversial response within the REST community.. watch the sparks fly!
>
> > What makes sense for return code if user already exists
> > and (a) is still in trial period, or (b) trial period has ended?
>
> (a) and (b): 200 OK!
>
> Why? Well, I believe you should clearly and cleanly separate your concerns
> between:
>
>    - simple hypermedia transfer, with corresponding status codes for that -
>    usually just 200, 301/2/4, 400/1/3/4, 500/2/4 are enough - and
>    - domain or application content-level interactions, with status declared

Jack Repenning

unread,
Apr 2, 2012, 1:48:52 PM4/2/12
to api-...@googlegroups.com
On Mar 26, 2012, at 8:30 AM, codingoutloud wrote:

> Care to share some of the more compelling reasons against 200 from
> your internal discussion?

Not part of the discussion you reference, but in working with my own consumers I've found that returning 200 and an error message caused problems in something rather like the original case 'b' ("trial period exhausted and insufficient info provided to create a paid account"). The problems arose from consumers coding to my API from the .NET framework. As it happens, I'm a Rails programmer, with no experience in .NET, so I'm not at all sure that I understand the nature of the problem reported, but the comment I got back from one user who had eventually figured it out was "I had to put in an extra loop."

What I take from this is that there was additional code needed to grub out the error message, and since the return status was OK he hadn't expected any error message, and hadn't written that code. For this reason, I try to make a return of "OK" mean "the thing you requested worked." Contrary to suggestions elsewhere in this thread, I do not separate transport-level failures from application-level errors, but rather treat basic notions like "success" or "failure" (2XX vs. 4XX returns) as global.

That doesn't help in choosing which 2XX or 4XX to return, of course. My reflex is to be "unsurprising," and that tends to rule out "subtle." If any old 4XX means "look at the error message for details," then have you really advanced matters any by returning the highly nuanced 402 "Payment required"?

You report that Apple has been known to use 402. Well, speaking as a certifiable Apple Fanboi, I gotta say ... Apple seems to adopt yet another new data connector, for disc or screen or something or other, with every new device they design. Five friends and I spent almost half an hour, yesterday, trying to string together dongles to connect an Apple laptop or iPad or the two together to a large-screen TV. There are many things I love about Apple, but the "really really no this time really even perfecter than last time connector for the same data standard" syndrome is not high on my list.


Jack Repenning

I do not know what I may appear to the world; but to myself I seem to have been only like a boy playing on the sea-shore, and diverting myself in now and then finding a smoother pebble or a prettier shell than ordinary, whilst the great ocean of truth lay all undiscovered before me.
-- Sir Isaac Newton


Matthew Bishop

unread,
Apr 3, 2012, 1:32:21 AM4/3/12
to API Craft

This sounds reasonable as long as both 201 and 200 return a Location
header pointing at the resource.

304 on a POST would be confusing. I would only expect that on a GET.

403/402 are good too. You could also send 409 to show the state is in
a conflicted state but that may be difficult for the client to
understand.

jrgns

unread,
Apr 26, 2012, 6:46:30 AM4/26/12
to api-...@googlegroups.com
I've also experienced that coders generally accept that 2xx codes meant that everything went well, and will ignore any error messages sent with that.This might be a misconception that needs to be changed if a separation of concerns as described by Duncan, which I think is something to work towards, is to be achieved.

There's been a discussion in the group on the correct response code partial failures for bulk actions, where a 200 code along with an error message was proposed. This will also require client dev's to add the extra loop.

On the other hand, a library like jQuery interprets anything between 200 and 300, and 304 as success, and the rest as fails (  https://github.com/jquery/jquery/blob/master/src/ajax.js#L520  ) . So returning 200 for a failure (even if the HTTP transaction succeeded) will "break" this kind of implementation.

This is a tricky question, which I think can best be solved by being consistent: If you use the HTTP response codes only for the HTTP transaction, and expect the client to check all responses (including 2xx) for errors, do that. Or, conversely, if you want to use the HTTP response codes in your application domain, send a 4xx, be it 400 or 402. Just document it as such.

Mike Kelly

unread,
Apr 26, 2012, 7:33:49 AM4/26/12
to api-...@googlegroups.com
On Thu, Apr 26, 2012 at 11:46 AM, jrgns <jurgens...@gmail.com> wrote:
> I've also experienced that coders generally accept that 2xx codes meant that
> everything went well, and will ignore any error messages sent with that.This
> might be a misconception that needs to be changed if a separation of
> concerns as described by Duncan, which I think is something to work towards,
> is to be achieved.

That is not a misconception. Using a 200 for (b) would be wrong, it
doesn't make any sense to do that. Invalidly attempting to create a
second trial is an error on behalf of the client, client errors are
what 4xx codes are for.

Cheers,
Mike

Arlo Belshee

unread,
Apr 26, 2012, 1:12:04 PM4/26/12
to api-...@googlegroups.com
Well, "2xx means OK" includes one misconception. It ignores 202, which intentionally states that the error state is currently unknown.

The fact that lots of client developers think "2xx == OK" makes it difficult to write servers that really do async processing. 202 is great if you own the clients. If you're handling generic clients, the "install base" of client developer thinking is too entrenched to really let you use it.

Thus people end up lifting async (a processing concern) to the resource level. They create resources like "transaction" or "batch" so that they can represent async without using the HTTP async primitives.

Oh well - another case where HTTP usable in practice is only a subset of HTTP in spec.

Arlo

mca

unread,
Apr 26, 2012, 1:21:02 PM4/26/12
to api-...@googlegroups.com
<snip>
The fact that lots of client developers think "2xx == OK" makes it
difficult to write servers that really do async processing. 202 is
great if you own the clients. If you're handling generic clients, the
"install base" of client developer thinking is too entrenched to
really let you use it.
</snip>
The members of this list are in the position to affect the trajectory
of client coding. Writing even "small|limited" clients that support
the behavior you want can make a difference and can spread the
knowledge to other places.

Be the change you want to see in the world - Gandhi

Arlo Belshee

unread,
Apr 26, 2012, 1:26:39 PM4/26/12
to api-...@googlegroups.com
<snip>
The members of this list are in the position to affect the trajectory of client coding.
</snip>

Agreed. Which is the only reason I even send an email which otherwise decries the woeful state of the universe, complains that someone on the internet is wrong, and offers to do nothing to fix it. :)

Of course, I can (and do when possible) use 202 correctly in my own APIs and clients.

Mike Kelly

unread,
Apr 26, 2012, 1:28:33 PM4/26/12
to api-...@googlegroups.com
Hi Ario,

On Thu, Apr 26, 2012 at 6:12 PM, Arlo Belshee
<Arlo.B...@microsoft.com> wrote:
> Well, "2xx means OK" includes one misconception. It ignores 202, which intentionally states that the error state is currently unknown.

2xx doesn't mean OK, 2xx means success - which is what the spec says:

"This class of status code indicates that the client's request was
successfully received, understood, and accepted."

Either way, Duncan's advice to use 2xx in response to a client error is wrong.

> The fact that lots of client developers think "2xx == OK" makes it difficult to write servers that really do async processing. 202 is great if you own the clients. If you're handling generic clients, the "install base" of client developer thinking is too entrenched to really let you use it.
>
> Thus people end up lifting async (a processing concern) to the resource level. They create resources like "transaction" or "batch" so that they can represent async without using the HTTP async primitives.
>
> Oh well - another case where HTTP usable in practice is only a subset of HTTP in spec.

Sorry, do you mean this is an 'issue' because you can't smoothly
switch a resource's behaviour from sync w/ 200 to async w/ 202? You're
right, that is impractical ! :)

Cheers,
Mike

mca

unread,
Apr 26, 2012, 1:34:09 PM4/26/12
to api-...@googlegroups.com
<snip>
Agreed. Which is the only reason I even send an email which otherwise
decries the woeful state of the universe, complains that someone on
the internet is wrong, and offers to do nothing to fix it.  :)
</snip>
LOL! we're cool.

Arlo Belshee

unread,
Apr 26, 2012, 1:56:17 PM4/26/12
to api-...@googlegroups.com
<snip>
Sorry, do you mean this is an 'issue' because you can't smoothly switch a resource's behaviour from sync w/ 200 to async w/ 202? You're right, that is impractical ! :)
</snip>

No, I mean that this is an issue because if I ever use a 202 response code to a request on an API for which I don't own the clients, then invariably people write clients that include code like:

if(response.status / 100 == 2) { // 2xx
handlers.success(response.head, response.body);
} else {
// possibly differentiate between 3xx, 4xx, and 5xx here, or not.
handlers.fail(response.head, response.body);
}

And then they get subtle errors and they (and their users) complain that there's a bug in the service (it isn't reporting an error when one happens).

If I can control or strongly influence the clients then I can use all sorts of HTTP features (partial GET, async processing, etc) that I can't use when I'm targeting a general client audience.

Arlo

-----Original Message-----
From: api-...@googlegroups.com [mailto:api-...@googlegroups.com] On Behalf Of Mike Kelly
Sent: Thursday, April 26, 2012 10:29 AM
To: api-...@googlegroups.com
Subject: Re: Response code when POSTing existing resource

Jack Repenning

unread,
Apr 26, 2012, 6:17:14 PM4/26/12
to api-...@googlegroups.com

On Apr 26, 2012, at 10:12 AM, Arlo Belshee wrote:

> Well, "2xx means OK" includes one misconception. It ignores 202, which intentionally states that the error state is currently unknown.

One might also include "207 - Multi-Status" in this rogues' gallery, since its purpose is to allow saying that parts of your request succeeded and other parts failed.

Jack Repenning

Invincibility is in oneself, vulnerability is in the opponent. That is why it is said that victory can be discerned but not manufactured.




Duncan Cragg

unread,
Apr 27, 2012, 1:46:42 AM4/27/12
to api-...@googlegroups.com
So this thread has picked up again, and there seems to be some confusion
here.

I don't think it's all that complicated, so I thought I'd have a go at
elaborating...

On 26/03/12 16:30, codingoutloud wrote:
> Duncan - thanks for this - this is sensible and clear thinking. I get
> that the SoC part and life will be hopeless if we try to map all
> business nuances into HTTP codes. The 200 indicates there was no
> problem with the HTTP session. The rest is business domain.

Exactly. Sensible and clear! :-)

I like to use the Web as my reference model - which doesn't always apply
in API-land, but can be useful (it certainly helps to remind people of
the success of just using GET and POST!).

Here's how we already separate our concerns on the Web without even a
second thought:

"Your new group has been created!" (200 not 201 Created)
"Your message may take a sec to show up in the forum" (200 not 202 Accepted)
"Your query returned no results" (200 not 204 No Content)
"You need to enter a valid email address" (200 not 400 Bad Request)
"Please log in using this nice form" (200 not 401 Unauthorized *)
"This content is only accessible to subscribers" (200 not 402 Payment
Required)
"Only our sys admins can go there, sorry" (200 not 403 Forbidden)
"The identifier you entered was not found" (200 not 404 Not Found **)
"Someone has just edited that - please try again" (200 not 409 Conflict)
"That account has been deleted" (200 not 410 Gone)
"Your file upload is too big" (200 not 413 Request Entity Too Large)

*.. this does start to cross the boundary for me - I think identifying
the user belongs in the headers, even if it is a Cookie, not an Auth.
It's only the browser's ghastly pop-up that forces people to go this route.
**.. from a form via GET

On the Web, the browser handles all the HTTP layer interactions, then
passes up the stuff in the content, or anything it can't deal with, to
the domain- or application-layer: to you!

Nice separation of concerns, leading to clean layering of code between
HTTP code and application code.

So now, imagine hitting all those scenarios in the list above with XHR,
and JSON! You'd possibly have JSON status codes and flags to indicate
these strings - all delivered by 200s up to the domain- or
application-layer code in your Javascript.

XHR should deal with cacheing, redirecting, etc.: 301/2/4. You'd
probably only need use 301/2/4, 400/1/3/4, 500/2/4 to interact within
the HTTP/XHR layer. So if you wrote some buggy code that sent a broken
header (can you do that with XHR?), then a 400 for you; if you hacked a
URL, then serves you right to get 403 or 404, etc. You'd probably hit
those as bugs, not in the course of an application interaction. If you
hit one, or a 500/2/4, you'd get an exception and have to recover as
gracefully as possible.

> Care to share some of the more compelling reasons against 200 from
> your internal discussion?

I'm afraid I couldn't discern anything compelling.. Sorry! :-)

Cheers!

Duncan

Mike Kelly

unread,
Apr 27, 2012, 2:22:53 AM4/27/12
to api-...@googlegroups.com
There is one extremely compelling reason, and that is that the semantics of the interaction are inconsistent with HTTP. This means that intermediaries will make incorrect assertions about the interaction..

i.e. you are violating the self-descriptive and, by association, layered constraints

So, as a practical example, if you insist on using 200 instead of 400 for erroneous requests - intermediating caches will invalidate the resource unnecessarily.

This may not be an issue for the specific approach described in the OP, but it is clear that there can and will be situations in which your advice that it "does not matter" will not hold water - often in situations where this would not be immediately obvious, too.

Just follow HTTP folks; if it's a client error use a 4xx.

Cheers,
Mike
Reply all
Reply to author
Forward
0 new messages