Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 9 additions & 59 deletions doc/error-formats-in-folio.md
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be worded as a recommendation? We don't have an approved decision record yet.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we limit it to new APIs?

Original file line number Diff line number Diff line change
@@ -1,63 +1,13 @@
# A modest proposal for error formats in FOLIO
# Error responses in FOLIO

> **NOTE.** This is a non-normative proposal, not at this stage a description of how things are actually done.
> Thu 12 Jan 16:59:27 GMT 2017

In almost all cases, when a server-side module needs to report an error to the client that invoked it, the HTTP status code conveys enough machine-readable information for the client software to decide what do (abort, retry, fail, ignore, etc.) But in a small number of cases, more expressive diagnostics are of use.

## Example

For example, one could imagine a client submitting an edit which fails validation on the server side: then the response could contain a list of validation-failure objects, each containing a fieldName, maybe the associated fieldValue that failed, and an explanation of why it was rejected:
APIs that supply JSON in "success" (2xx) responses with a content-type header of "application/json" must likewise supply JSON in "error" (4xx, 5xx) responses with a content-type header of "application/json".
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APIs that supply JSON in "success" (2xx) responses with a content-type header of "application/json"

I don't see a need for this limitation.

An API that returns 204 (= non content) on success should return a JSON with error details on failure.

An API that returns a CSV text on success should return a JSON with error details on failure.


The response object must contain either a top-level property `message` or a top-level property `errors` that contains an array of objects with `message` properties. That is, a response object must be shaped like this:
```
400 Bad Request
Content-Type: application/json

{
"errorCode": "ValidationFailed",
"message": "Some submitted fields contained invalid values",
"details": [
{
"fieldName": "phone",
"fieldValue": "01279 504 468",
"explanation": "value must not contain spaces"
},
{
"fieldName": "email",
"fieldValue": "demon.co.uk!n4!mirk",
"explanation": "UUCP-style mail addresses are not supported"
}
]
}
{ message: "", ...}
```

A clever UI could use this to annotate its edit page and guide the user.

## Proposal

We suggest that FOLIO modules may return errors to clients in either
of two formats: a simple plain-text message, or a structured JSON object.

* HTTP status is king -- always convey information via that first.
* When the status is 4xx or 5xx, the response body contains additional error information.
* Additional error information may be `text/plain` or `application/json`.
* When it is `application/json`, it must always be an object containing an `errorCode` key whose value is an opaque code taken from a vocabulary that we will establish (possibly namespaced by module).
* The object must also contain a `message` key whose value is a human-readable string like the one that would have been used if the content had been `text/plain`.
* Additional keys within the JSON structure, if any, are dependent on the `errorCode`: documentation of each code includes a specification of what additional fields are included, and their types and meaning.

## Consequences

If this convention is adopted, then any back-end module can easily upgrade a given error report from the basic text/plain form to a superset JSON error object as and when needed.

When receiving an error response, it is the responsibility of the client to check the content-type and be prepared to handle either plain text or JSON. If the client runs into a JSON error that it doesn't know how to handle, then at least it knows to use the `message` element of the object as the error-message. More sophisticated handling can be added on the client side as and when.

It might make sense if there are error codes not covered by HTTP but needed across a variety of modules to provide a set of standard error codes but require that any codes not on the list, use a module-based namespace encoding.

Since we have no immediate need for structured error information, there is little gain _now_ from adopting this approach. But it will be a big win down the line when we decide we need more expressive power in diagnostics. The ugrade path is very painless, as individual errors on the server side can be upgraded as and when; and no such change will require a corresponding UI change, the additional information will just be there for the UI to use when it's ready.

So upgrading the format of an error reported by service doesn't break anything.

## Special case: multiple errors

If for some reason a service wants to report multiple unrelated errors in a single response, it could do so using the error-code `MultipleErrors` and providing a `details` array each of whose elements is an error object like the top-level one. (I am not sure there is really a need for this, but it's worth pointing out that this simple proposal does cover that complex case.)

or like this:
```
{ errors: [{ message: "", ...}, ...]}
```
These are the only required properties. Additional properties at any level are optional.