Hacker News new | ask | show | jobs
by caseysoftware 3231 days ago
No.

You should never, ever, ever return a 2xx status code with an error payload. The 2xx series means "Success" and you're abusing HTTP to use it to mean anything else.

With regard to application layer vs transport layer, the 404 Not Found, 406 Not Acceptable, 409 Conflict, and many others errors are specifically application layer codes. If you can't get a more specific code, 400 Bad Request with an expressive payload is useful. The 500 codes are generally transport layer.

The reason that APIs are getting easier and easier to understand and use is because we're using the same design patterns consistently and repeatedly. Therefore, the understanding you gain from the Twilio API can be applied to Stripe. If you use existing tools in new and "innovative" ways that are contrary to - instead of in addition to - to their intention, you're setting back adoption and making your users re-figure out basic things. Don't.

Or worse, people don't realize how you're misusing the tools and build flawed systems.

(The one exception I'd give you is 202 Accepted which is generally used for "we've accepted this for now but processing and final validation may occur later" - it's a tentative success message.)

2 comments

> You should never, ever, ever return a 2xx status code with an error payload. The 2xx series means "Success" and you're abusing HTTP to use it to mean anything else.

If the transport was successful, then it was an HTTP success.

> 404 Not Found, 406 Not Acceptable, 409 Conflict, and many others errors are specifically application layer codes

These are "application specific" to the resource only, not to the API as a whole. Nor are they particularly informative which is why the spec advocates incorporating a more specific error message. At best, these codes describe a class of errors, possibly useful for logging, but not sufficient for a nontrivial API's error semantics.

My point is not that the HTTP status codes don't mean anything, it's that they are misused to describe application level stuff and used to handle application layer flow control in a way that defeats the purpose and makes them more confusing than they are worth much of the time.

> because we're using the same design patterns consistently and repeatedly.

This is absolutely not the case, every team overloading HTTP status codes seems to do it their own quirky way.

The worst part is when people start bikeshedding about the subtle meaning/intent of HTTP status codes (as your point about 202 illustrates). The simple solution is to define the relevant application layer errors for a specific API and use the HTTP status codes for transport related stuff. It should not matter what 418 or 202 means because the subtle meanings they get int he context of one API/application should not be relevant.

Uh what? If the request was appropriately formatted, not too large, and generally acceptable to the server from a transport perspective, why shouldn't it succeed with a 200?

Error handling is an application level concern, not a transport level concern.

HTTP status codes lack the nuance required to inform the end user about errors in any non-trivial application. I personally enjoy the OP's solution. I've worked on dozens of REST APIs in my life, and I always prefer those that contain a response envelope complete with metadata and error responses.

Pre-emptive edit: When I say error handling is an application level concern, I don't mean "application" from an OSI model perspective, which is narrower in scope than what I'm talking about.

Expressive error messages are great. Calling errors a "success" is wrong.

Check out my slides here for more: https://speakerdeck.com/caseysoftware/12-reasons-your-api-su...

Slides 38-40 are specifically about expressive and useful error messages.

Your slides illustrate a custom response payload which happens to use codes that numerically match HTTP status codes. You also use a response message, I think we actually agree. I'd recommend using a different numerical namespace to avoid any possible confusion about the semantics of those codes. Just because they sound the same to one person reading the spec doesn't mean they will make sense to others.
Understood on that point. The response codes are in those payloads purely for illustrative purposes.
>appropriately formatted

If the server is expecting data that it doesn't receive (because the form field was left blank) then can you really consider the request "appropriately formatted"? Is it in any way meaningfully different from the case where the server receives a request on /api/invalid-url/ and doesn't have a corresponding resource on its end?

By that logic nearly all errors are formatting errors.