HTTP status code for business logic errors

7,471 views
Skip to first unread message

Joseph

unread,
Mar 18, 2014, 1:29:26 PM3/18/14
to api-...@googlegroups.com
Hi,

We have a custom platform that provides REST services for eCommerce exposed through app/web tiers and are consumed by Java/Javascript clients. We are trying to standardize on the way errors are communicated for various scenarios and need some guidance on how business logic errors should be handled. An example is "credit card authorization" failure. This error would be known only when we communicate with the card authorization system and it sends a "declined" response. These kind of errors needs to be differentiated from client validation errors which can be caught internally by the service (ex: invalid credit card length) and sent as HTTP 400, along with the response body containing a custom error code and message detailing the error. 

What would be the right HTTP status code to use for business errors like the one described above? . We have reserved HTTP 500 for server errors that do not give ANY response - i.e timeouts, internal code exceptions etc, and want to use 200 only if the request has completed successfully - i.e it's a success from the business and user's  point of view (ex: card authorization succeeded). Please share your inputs on this.

Thanks,
Joseph

Jack Repenning

unread,
Mar 18, 2014, 1:54:23 PM3/18/14
to api-...@googlegroups.com
On Mar 18, 2014, at 10:29 AM, Joseph <jaa...@gmail.com> wrote:

What would be the right HTTP status code to use for business errors like the one described above? . We have reserved HTTP 500 for server errors that do not give ANY response - i.e timeouts, internal code exceptions etc, and want to use 200 only if the request has completed successfully - i.e it's a success from the business and user's  point of view (ex: card authorization succeeded). Please share your inputs on this.

Yes, it should be something from the 4XX range. 2XX means "all cool," which this isn't; 5XX means "the server screwed up," which this also isn't.  4XX means "the corrective action is up to the user," in this case, perhaps, using a different card.

I think 403 "Forbidden" looks like the closest match[1]: "The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated." 409 "Conflict" might also apply: "The request could not be completed due to a conflict with the current state of the resource." But "This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request," which doesn't seem to apply here.

Whichever status you choose, you should expect the caller to need additional info. The "Problem Details for HTTP APIs"[2] response draft standard is the best way to provide it.


[1] http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
signature.asc

Joseph Anish Alex

unread,
Mar 18, 2014, 2:41:58 PM3/18/14
to api-...@googlegroups.com
hi Jack,

The card authorization failure was just an example. We use 403 for security authorization failures like invalid session, so would like to keep those system level errors separate from business errors. I think 409 seems to fit more since the user can resolve the conflict by using another card ; interpreting "conflict" as a mismatch between the given input and the set of rules it should pass through before the request is considered successful. What are your thoughts on responding with HTTP status 409 along with a machine-readable error code in response body for all such cases, or do we need to consider this case by case? 

Thanks,
Joseph

Jack Repenning

unread,
Mar 18, 2014, 2:50:22 PM3/18/14
to api-...@googlegroups.com
On Mar 18, 2014, at 11:41 AM, Joseph Anish Alex <jaa...@gmail.com> wrote:

What are your thoughts on responding with HTTP status 409 along with a machine-readable error code in response body for all such cases, or do we need to consider this case by case? 

That sounds mostly fine. I'm a little put off by the phrase "machine-readable error code." There's always at least one human involved (the programmer of the API client), and sometimes others (like, the user offering the card, or scanning it as case may be). The human deserves support as well as the machine. This is part of why I suggested the "Problem Details" draft standard: it specifies a response that includes at least three kinds of info:
  • machine-readable, single-valued status (say, "409")
  • human-readable explanation (say, "card declined," to continue with your specific example)
  • machine-traversable links to explanations and, if relevant, next steps

If you're writing the client code, you might think to translate status codes into human description in the client, but this falls apart quickly, into sub-status codes, and constant need to update the client just because the server learned to detect yet another failure mode. Better to keep the semantics of the code simple, coarse-grained, and actionable: "Refuse the transaction, and display this string to explain why."

-- 
Jack Repenning
Repenni...@gmail.com

signature.asc

Joseph Anish Alex

unread,
Mar 18, 2014, 3:06:05 PM3/18/14
to api-...@googlegroups.com
By machine-readable, i meant that the error code sent in the response body that can be interpreted by the client program. For the auth failure example, it would be HTTP status 409, and the "code" field in response body, like : 

{
    "response": {
        "code": "payment.auth.failed",
        "message": "Payment authorization failure"
    },
    
    "more-details-node" : "...other details related to the card.."
    ..
    }

The client code can map "payment.auth.failed" to a user-friendly message say "Your credit card was declined. Please use a different card" , since the service layer does not want to be responsible for maintaining the UI messages.

Jack Repenning

unread,
Mar 18, 2014, 3:08:27 PM3/18/14
to api-...@googlegroups.com
On Mar 18, 2014, at 12:06 PM, Joseph Anish Alex <jaa...@gmail.com> wrote:

The client code can map "payment.auth.failed" to a user-friendly message say "Your credit card was declined. Please use a different card" , since the service layer does not want to be responsible for maintaining the UI messages.

"Model / View / Controller" architecture is calling your name ;-)

-- 
Jack Repenning
Repenni...@gmail.com

signature.asc

Rossitsa Borissova

unread,
Mar 27, 2014, 5:34:54 PM3/27/14
to api-...@googlegroups.com
Hi,

I'm not sure what is the best choice for HTTP status in that case (authorization failed) but 409 does not look the most appropriate one to me.
What is the conflict in case of authorization failure?
Let's say if two identical authorizations are on their way (to be processed) that might be a real conflict. But that does not seems the case.
Also, 200 OK might not always mean a successful response in business point-of-view, it means that the request has succeeded.
You may use 201 created if an authorization is successful.
The question of HTTP response statusес and codes has always been a reason for heated arguments.

Best regards,
Rossi

Joseph Anish Alex

unread,
Mar 28, 2014, 12:21:13 AM3/28/14
to api-...@googlegroups.com
Hi Rossi,

The 409 is interpreted to mean a mismatch (aka conflict) b/n the original request and rules that need to pass for the API to succeed from business point of view. So, it's not exactly the HTTP spec meaning of 2 . I understand the view that 200 need not mean a business success, but our team wanted to have 200 denote a complete success - both system and business-wise. Hence this direction.

Thanks,
Joseph


--
You received this message because you are subscribed to a topic in the Google Groups "API Craft" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/api-craft/_dfnBKImNCI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft.
For more options, visit https://groups.google.com/d/optout.

sune jakobsson

unread,
Mar 28, 2014, 6:05:41 AM3/28/14
to api-...@googlegroups.com
Have a look at http://www.gsma.com/oneapi/payment-restful-netapi/
where we used 201 for a successful payment, and 403 for screw-ups of
misc kind.

Sune
> You received this message because you are subscribed to the Google Groups
> "API Craft" group.
> To unsubscribe from this group and stop receiving emails from it, send an

snow6oy

unread,
Mar 31, 2014, 2:27:58 PM3/31/14
to api-...@googlegroups.com
Hi all,

Interesting thread. In our API design we took a different approach. Our implementation always sends a 200 Ok to indicate that the server has got the message, but that doesn't necessarily mean that all the business logic has been fulfilled. We decided to provide both HTTP and Custom error codes for every possible scenario. When the error is about communication at the protocol level (e.g. Invalid Media Type) then the custom code mirrors the HTTP status. But when we have a domain-specific error, equivalent to "credit card authorization failure" then we send 200 Ok and defer to the custom error handling to elaborate.

The APIs have been in production for over a year and the feedback has generally been great. But our approach to the 200 is the area that has received the most criticism and is probably the one thing that we would do differently next time. Developers find it confusing but unfortunately we can't easily change our strategy at this point. 

Gavin

Dietrich Schulten

unread,
Mar 31, 2014, 3:23:07 PM3/31/14
to api-...@googlegroups.com

In my opinion it is important to consider how a client can recover from the error condition. This should not be based on out-of-band information. Building an arcane system of error codes where you redefine or restrict the meaning of status codes (403 is system, 409 is business) seems not so wise. Some HTTP status codes do define strategies for the client to follow on the application protocol level. If these are not sufficient, the server should guide the client by returning a document which contains the necessary hyperlinks to recover. In other words, use hypertext as the engine of application state. Return a document that has an action to try another card. That document represents the error state of your application. The client did nothing wrong, therefore 200 is appropriate.
See the uber mediatype for a suitable media type that supports actions [1] . There are others which are based on json (hydra, siren)

[1] https://rawgithub.com/mamund/media-types/master/uber-hypermedia.html

Reply all
Reply to author
Forward
0 new messages