An error contract you can version
One error shape, a machine-readable code, a human-readable message nobody parses, and a rule about what never leaks out.
Pick one envelope and use it everywhere, including in the middleware that catches what you did not expect. A code the client can switch on, a message a human can read, and optionally a field-level list for validation failures. The code is the contract; the message is documentation that happens to travel over the wire, and the moment a client string-matches on it you have made a copywriting change into a breaking change.
Field-level errors deserve structure rather than a sentence. A list of objects with the field path and a reason lets the client mark the right input red, which is the whole reason it asked. A single string forces the front end to either display it raw or parse it, and both of those are worse than the array you could have sent.
On leakage: stack traces, SQL fragments, upstream hostnames and library versions do not belong in a response body. Log them with a request id and return that id to the caller instead. A user who can quote a correlation id to support is more useful than one who can quote a stack frame, and an attacker learns nothing from a UUID.
You should now be able to
- Design a single error envelope for a whole service
- Separate the code a client branches on from the text a person reads
- Decide what detail is safe to return
Loading…