Hacker News new | ask | show | jobs
by pokoleo 1564 days ago
The error messages could be better yet.

The example uses a different code per issue, for instance: "user/email_required". Most integrators will build their UI to highlight the input fields that contain an error. Making them parse the `code` field (or special-case each possible code) is pretty toilsome.

    // from blog post
    {
        "code": "user/email_required",
        "message": "The parameter [email] is required."
    }
Make it parseable:

    // improved
    {
        "message": "An email is required.",
        "error": "missing_parameter",
        "parameter": "user.email"
    }
In addition, I:

* rewrote `message` to be an acceptable error message displayed to (non-technical) end-users

* moved message to be the first field: some developer tools will truncate the JSON response body when presenting it in the stack trace.

---

As an added bonus, structured data allows you to analyze `error` frequencies and improve frontend validation or write better error messages: https://twitter.com/VicVijayakumar/status/149509216182142976...

6 comments

It might be to formal for your use-case, but there is a standard defined for error responses in RFC 7807:

https://datatracker.ietf.org/doc/html/rfc7807

Wow, I had never seen an API with errors at this level of detail… I feel lucky when they at least use sane status codes instead of always giving back 200 and a maybe-json-maybe-plaintext-maybe-empty body…

I’d love to hear from anyone who has encountered APIs in the wild that actually implement this standard!

I used to work at Akamai and Problem Details is used in most of their APIs. It might have something to do with the fact that one of the RFC authors (Mark Nottingham / @mnot on HN) worked there for a while.
I've used both Problem Details and JSONAPI errors[0] which are basically the same idea (and I've used them plenty outside of JSONAPI-proper APIs). In both cases if you have a decent error-handling middleware there should be not much difference than outputting any other kind of errors.

One thing to keep in mind re. "maybe-json-maybe-plaintext-maybe-empty" responses is that the more complex your errors, the more likely the error handling encounters an error. If you're trying to send back some JSON or XML but it fails it's usually better to at least shove out a line of plain text and hope it reaches a human than to mask the real error with a second fallback in the "right format" but with unhelpful fixed content.

[0] https://jsonapi.org/format/#error-objects

I use Problem Details in most APIs I build. It’s as simple to generate a Problem Detail as it is to generate ad-hoc errors, but you can re-use code.
I think stripe is close to having decent API in this regard
That is stupid. Most of our failed requests are logged and logs are only read by dashboards and alarms. Sure, you can have a friendly message too but formalizing the errors in a structured way simplifies things and also improves the performance when scanning through large amount of logs.
Such simple approach is limited only to errors without arguments.

For more complex use cases, where we would want an error message to indicate that field value was too long and in addition provide maximum field length, we would need to introduce new field in the error response.

While it is solvable by adding this information to client application side. It would create a situation where the logic is duplicated in two places (backend and client application)...

Also if we would want better UX, then we would need to display all errors at the same time in the form that is incorrectly filled. This would require changing error structure to return array of errors and it potentially create a breaking change in the API or would result in confusing structure that supports both, legacy and new format...

Some years ago, I wrote an article sharing the ideas on how REST API error structuring could be done depending on the complexity of application or service: https://link.medium.com/ObW78jhDkob

Interesting! Do you find that returning an array of errors works in practice?

Most validation I’ve seen looks like:

    raise error if foo
    raise other_error if bar
This pattern turns into one exception per response, and some foresight in architecting exceptions would be needed
From my experience it serves very well for validating inputs of large forms - e.g. loan application, international payments, etc.

If you need to validate some business logic like if sender's account has funds and receiver's account is not blocked, then this approach starts to look a bit strange. I would guess that the most of the time developers would implement checks so they would fail on first condition and would not check later one. This would result with single error in the array that kinda would look strange.

Validating business logic and returning several errors at the time requires good knowledge of the domain and in depth design of the system you are working. As this creates more complexity and slows down delivery, most of the time it is ditched and used only for particular use cases.

We could say that this would be more applicable to corporate solutions, but IMHO it really depends of the scale of the project, man power and the user experience you would want to create.

The Phoenix framework does this for forms. It requires a whole system built around a type called a Changeset that describes input parameters, their validity, and how to modify a struct to reflect the valid changes. In practice this ends up tightly coupled to the database layer for simplity.
Does "tightly coupled with the database" work, in practice?
It's only tightly coupled if you let it be. You can create changesets around any data shape, whether thats connected to your schema' table, a partial view of a table or entirely independent.
Localization has entered the chat.

You need codes because the field isn't going to be 'email' for much longer than it takes for your management to realize that people outside of the US also have wallets.

Field ids are not (necessarily, especially when doing localization) something shown in the UI. The point made by the original commenter is that a field in the error should refer directly to which field has an issue. It does, via an id that happens to be "email". It's still up to the clients to decide how to represent that to the user, but they're given a distinct field rather than needing to infer which field an error code refers to.

(While the comment I replied to can be read differently, I assume we all know that changing actual field names (in APIs) depending on localization is nuts)

No doubt they exist, but I’ve never seen an api that localised identifiers.
My view is that apis should simply return a number when an error occurs. The vendor should supply a list of error codes to its consumers, translated into as many languages as necessary. The developers who are consuming the api can then determine how best to present the error to its end users. A set of error numbers is tied to the version of the api that is being consumed so there should be no surprises.
In other words, if a set of people don't understand the message, make sure that no one understands the message (not even the people that normally just press the Google Translate button).

Is that what you're saying? Or did I misunderstand you?

Agreed. But rather than reinvent, let’s just use JSON API standard?

https://jsonapi.org/format/

(Scroll to the very bottom)

The article is about REST API design, not JSON APIs! It’s a whole different ballpark.
It also doesn't hurt to repeat the HTTP status code in the JSON body - when you receive a response, the status code and entity body are coupled but even if the server logs the status code, they're often decoupled in the logging system - having both in one log entry is way easier!
Hey thanks for your input. These are great additions!