146

I'm creating a RESTful API that will process a number of user interactions, including placing orders using stored credit cards.

In the case of a successful order, I'm returning a 200 OK, and in the case where the order request is malformed or invalid I'm returning a 400 Bad Request. But what should I return if there is a problem during the actual processing of the order?

  1. Client POSTS order to server for a user resource. If user does not exist, 404 Not Found is returned.
  2. Order format and information is validated. If not valid, 400 Bad Request is returned.
  3. Order is processed. If the order is successful, a 201 Created is returned for the order. If an unexpected error is encountered, a 500 Server Error is returned.

The last step is the problem - what do I return if the order doesn't complete for any other reason? Possible scenarios could include:

  • Product is sold out
  • User maximum order limit reached
  • Credit card transaction failure (insufficient funds, etc.)

This doesn't seem like it would be appropriate for either a 400 or 500. If anything I could see it as a 400 if there's no better code - the request was invalid according to the business rules. It just doesn't seem accurate.

Edit: Also found this existing discussion of the same topic. All of the answers there seem to point to using status codes for this type of violation, with some discussion between using 400, 409, or the 422 extension.

Community
  • 1
  • 1
Raelshark
  • 2,975
  • 3
  • 27
  • 36
  • 10
    I like '422 unprocessable entity' for validation errors. And would use it for your above examples, include a message in the response with the actual business issue "Product is sold out" and possibly add your own 'codes' if the client needs to programmatically make different decisions based on the response – house9 Oct 16 '15 at 00:19
  • 1
    before you jump into 422, consider if you support WebDAV capabilities – Mbithy Mbithy Feb 25 '19 at 16:23
  • 1
    Just dropping this here for future reference. As of June 2022, 422 is no longer a WebDAV code. It is general use (RFC 9110). – Sinaesthetic Mar 10 '23 at 18:25
  • The way that 422 is written now kind of implies that it is best suited for business rule validation failures. For example, 'foo' is valid and 'bar' is valid, but it doesn't make sense to use 'foo' if 'bar' is present. – Sinaesthetic Mar 10 '23 at 18:36

7 Answers7

121

You should use 4xx for business rules. Don't return 2xx if the order was not accepted. HTTP is an application protocol, never forget that. If you return 2xx the client can assume the order was accepted, regardless of any information you send in the body.


From [RESTful Web Services Cookbook][1]:

One common mistake that some web services make is to return a status code that reflects success (status codes from 200 to 206 and from 300 to 307) but include a message body that describes an error condition. Doing this prevents HTTP-aware software from detecting errors. For example, a cache will store it as successful response and serve it to subsequent clients even when clients may be able to make a successful request.

Max Toro
  • 28,282
  • 11
  • 76
  • 114
  • 1
    Do you have any examples or references for this approach versus the other? Both your and Widor's answers make sense, one from the perspective of HTTP as an application protocol, and the other as it being strictly for the purpose of the transfer. The spec defines it as an "application-level protocol", which is a little vague. I've also seen both perspectives and examples around the web when researching this. – Raelshark Feb 21 '12 at 21:27
  • 1
    this is so true. – Young Hyun Yoo Nov 20 '17 at 13:29
  • 6
    Do you mean, 'You should use 4xx for business rules'? – Yawar May 16 '18 at 12:53
  • I am assuming we are discussing HTTP status code in the context of a RESTful HTTP service. I read Dr. Fielding's dissertations a few times. One of my interpretations of Dr. Fielding's thesis was that REST is a set of guidelines that helped shape/architect the web. And in the web I don't see 400's being returned for business rules errors. Therefore, I am inclined to use 200's for business rules, and the HTTP response body elaborates on the business error. Now this would be different for request parameter validation where the parameter is clearly invalid as per contract -- that is a 400. – rubens Mar 04 '21 at 19:52
  • I'm also curios about the topic, since according to the HTTP spec, 400 means that request is beyond repairing and must not be repeated. The uses cases that OP has presented are not like that. The request is valid, and can be repeated. – iwat0qs Mar 24 '22 at 08:21
38

You should use 4xx for a client error if the client can modify the request to get around the error. Use a 5xx for a server error that the client can't really work around.

Product sold out would be a server error. The client can't modify the request in some fashion to get around the error. You could switch to another product but wouldn't that be a new request?

User maximum order limit reached is also a server error. Nothing the client can do to work around that error.

Credit card transaction failure would be a client error. The client could resubmit the request with a different payment method or credit card number to work around the error.

Paul Morgan
  • 31,226
  • 3
  • 24
  • 27
  • 10
    If the order limit is reached, shouldn't the client alert the user to that and let them change their request appropriately? That seems like a 4xx error. Same goes for the product being sold out. 5xx errors are intended for errors that are caused by the system breaking down in some way, not for an action that's disallowed by a business rule. – carlin.scott Dec 14 '15 at 19:35
  • 9
    I agree with the comment above. 5xx errors are for when the server has problems. 4xx errors for business rules. – Merc Feb 19 '17 at 06:39
  • As I mentioned in my other comment, I'm also curious about the topic, but the reasoning that this is a client problem doesn't solve it for me. 400 means the request is invalid beyond repairing, according to the HTTP spec. There's no sense in retrying it again. But for all of the use-cases that OP has mentioned, the request is worth repeating without any changes. Items can be restocked, limits can be reset, and transactions can be retried. Insufficient funds in neither a client's nor a server's problem. – iwat0qs Mar 24 '22 at 08:25
30

Error type:

4×× Client Error

Error code:

422 Unprocessable Entity

The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.

For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

https://httpstatuses.com/422

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
stamster
  • 953
  • 11
  • 18
22

I know this question is old, but I came up with the very same question today. If my user runs out of credits, what status code should my REST API return?

I tend to lean towards 402 Payment Required:

According to Wikipedia:

Reserved for future use. The original intention was that this code might be used as part of some form of digital cash or micropayment scheme, but that has not happened, and this code is not usually used. Google Developers API uses this status if a particular developer has exceeded the daily limit on requests.

And indeed they do:

PAYMENT_REQUIRED (402)

  • A daily budget limit set by the developer has been reached.
  • The requested operation requires more resources than the quota allows. Payment is required to complete the operation.
  • The requested operation requires some kind of payment from the authenticated user.
Community
  • 1
  • 1
BenMorel
  • 34,448
  • 50
  • 182
  • 322
7

How about 424 Failed Dependency? The spec describes it as:

The method could not be performed on the resource because the requested action depended on another action and that action failed.

But there is also this definition:

Status code 424 is defined in the WebDAV standard and is for a case where the client needs to change what it is doing - the server isn't experiencing any problem here.

You can tell the client (or pretend) that you have internal actions which are supposed to create the order, and deduct the balance, and that one of those actions failed, albeit for perfectly valid reasons, and that's why the request failed.

As far as I can see, "action" is quite a broad term, and can be used in a variety of situations, including insufficient stock, insufficient credit, or warehouse party night.


Another option might be 422 Unprocessable Entity:

The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.

For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

Trying to request an item which is out of stock, or when you have insufficient credit, might be considered a mistake at the semantic level.

MozDev says this indicates a mistake on the client side, specifically: The client should not repeat this request without modification.

Loopback 4 uses 422 when input validation fails.


Arguably, insufficient stock or warehouse party night could be considered temporary states, so the request could be retried again later. That situation can be indicated by 503 Service Unavailable

The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.

The server MAY send a Retry-After header field to suggest an appropriate amount of time for the client to wait before retrying the request.

joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
2

I do'nt think 400 can be used for all the business scenario. It can be used for basic data input validation. Beyond that we might have hard to time fit other business logic into this error code. The error handled by this are mostly design time errors which developer will encounter possibly during the coding of the client.

Let's say all parameters are correct and let's say we are passing user account number into the request.

So request is now no longer a bad request, the server is able to accept the request. But now it is refusing to fulling the request based on new information available which is - account does not have sufficient balance.

I would suggest we should use 403 with appropriate error message in those scenarios.

Other possible error code could be 409 conflict. But that is used in scenarios where the resource is in in consistent state.

Rajender Saini
  • 594
  • 2
  • 9
  • 24
-1

I go with 406 Not Acceptable.

Here's a 4xx list:

const HTTP_BAD_REQUEST = 400;
const HTTP_UNAUTHORIZED = 401;
const HTTP_PAYMENT_REQUIRED = 402;
const HTTP_FORBIDDEN = 403;
const HTTP_NOT_FOUND = 404;
const HTTP_METHOD_NOT_ALLOWED = 405;
const HTTP_NOT_ACCEPTABLE = 406;
const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
const HTTP_REQUEST_TIMEOUT = 408;
const HTTP_CONFLICT = 409;
const HTTP_GONE = 410;
const HTTP_LENGTH_REQUIRED = 411;
const HTTP_PRECONDITION_FAILED = 412;
const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
const HTTP_REQUEST_URI_TOO_LONG = 414;
const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const HTTP_EXPECTATION_FAILED = 417;
const HTTP_I_AM_A_TEAPOT = 418;                                               // RFC2324
const HTTP_MISDIRECTED_REQUEST = 421;                                         // RFC7540
const HTTP_UNPROCESSABLE_ENTITY = 422;                                        // RFC4918
const HTTP_LOCKED = 423;                                                      // RFC4918
const HTTP_FAILED_DEPENDENCY = 424;                                           // RFC4918
const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425;   // RFC2817
const HTTP_UPGRADE_REQUIRED = 426;                                            // RFC2817
const HTTP_PRECONDITION_REQUIRED = 428;                                       // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429;                                           // RFC6585
Mahmoud Zalt
  • 30,478
  • 7
  • 87
  • 83
  • 10
    While the name of status code 406 might sound accurate by itself, you need to be aware that each status code has an authoritative textual description. The description for status code 406 *is not suitable* for the case at hand. See https://httpstatuses.com/406, for example. – Zero3 Jan 27 '17 at 15:46
  • 2
    @Zero3 is right, this code means the response type is not acceptable, as there is a mismatch between the Accept Headers sent from the client and the MediaType(s) sent by the endpoint, e.g. application/json vs. text/plain – Gregor Feb 15 '18 at 17:42