Hacker News new | ask | show | jobs
by stickfigure 2899 days ago
Repurposing HTTP error codes conflates your application-specific errors unless it maps to an exact subset of one of the predefined errors.

...and beware even the errors that match exactly! I've seen multiple systems in the wild that treat 404 as an application-specific error for "content not found". It sounds perfectly reasonable at first, but it puts you one misconfigured reverse proxy away from inadvertently broadcasting to the world that all your content is gone.

This can have data-corrupting effects. If an external system deletes resources via a reliable message queue and treats 404 as a success condition, they run the risk of dropping these messages and creating an inconsistent state. I've seen it happen.

Keep application-specific error messages distinguishable from the 'plumbing'.

4 comments

That seems like a bug with the external system. 4xx means the request needs to be corrected to achieve success. 2xx means success, even if success means "deleted".

If a system treated 5xx responses as successful, you'd consider that a problem with the system's response handling, not a problem with your own communication of state. So why consider abuse of 4xx to be a problem with the communication protocol?

The external system didn't define the API; the service did. If you poke around on stackoverflow, you'll find quite a number of answers recommending this pattern. It's a bad idea, but it's not uncommon.
Recommending what, that a `DELETE /foo/bar` should return a 404 on success? That's flat-out wrong. It should return a 204 No Content. A subsequent `GET /foo/bar` should return a 404, but presumably the message queue isn't doing a subsequent GET but is inspecting the result of the DELETE.
Ok. But again, a bad design choice doesn’t mean using HTTP error codes is a bad idea. It means that like with anything else you need to know your tools.
If it's put in a message queue, use a 202 Accepted somewhere, if it's added with HTTP requests ? 201 Deleted only if deleted in real-time. Then check later for proper deletion on or push status of the job to the consumer. 404 as a success condition does not seem to be reliable to me
So.much.experience and wisdom in this answer. I learned something new today. Thank you.
> If an external system deletes resources via a reliable message queue and treats 404 as a success condition, they run the risk of dropping these messages and creating an inconsistent state. I've seen it happen.

This would reflect an incorrect design on the part of the external system.

For example:

  PUT /queue/_hyn3
  => {"name": "_hyn3"}

  GET /queue
  <= {"name": "_hyn3"}

  ... processing ...

  GET /queue/_hyn3
  404
404 is not a success condition; it's also not necessarily a permanent error.

Queues might be "reliable", but the consumers should never be assumed to be, and so it's good to have consumers provide a "complete" state update somewhere, and ideally, if the queue is able, for the queue to restore the incomplete item if the consumer fails to complete it in a specific (lengthy) period of time, because the consumer itself might have ceased to exist or failed for some other reason.

If you need to ensure that each message is consumed once and only once, you need to ensure that your queue also has something like a "completed state":

  PUT /queue/_hyn3
  => {"name": "_hyn3"}

  GET /queue
  <= {"name": "_hyn3"}

  ... processing ...

  PUT /status/_hyn3
  {"name": "_hyn3", "status": "completed"}

  GET /queue/_hyn3
  404

  GET /status/_hyn3
  {"status": "completed"}
Obviously, there's an infinite number of ways to handle the semantics here, and certainly REST is not constrained in any way to just JSON, and perhaps you would prefer to put completed in the URL, but the point is that the architecture needs to support such a use case. TL;DR: don't rely on 404 as a permanent error, but it's absolutely appropriate for a document/content/file not found, even if the content will be found later or was found earlier.