The situation is such that I use the axios library and interceptors of successful and unsuccessful requests in order to automatically pick up and display an alert with the error text from the server in case of an error.
So my backend developer sends me error messages that are not suitable for output to an alert arguing that the message is I have to generate the error myself, but what comes from the server is only needed so that I know about the error. Is he right, or sending an error message from the backend should go strictly like response.message
and match the error format displayed to the user on the UI?
The universal error interceptor that I spoke about looks like this, but the errors that it sends to me each time are on a different path, while their format is not suitable for displaying to the user, and often an array with errors comes to the request. Is he doing the right thing?
Because in that case, I cannot use the code below to handle errors
const API = axios.create({
baseURL: '/api/',
responseType: 'json',
headers: { 'cache': 'no-store' },
})
const onFulfilled = (response) => response.data
const onRejected = (error) => {
if (error.response?.status === 500) {
notify(error.response.statusText || ' Internal server error', 'error')
} else if (error.response?.data.message) {
notify(error.response.data.message, 'error')
} else {
notify('Oops something went wrong', 'error')
}
..... and so on
return Promise.reject(error)
}
API.interceptors.response.use(onFulfilled, onRejected)
This is a classic dilemma, especially when projects are young and everything happens fast. There's an immediate answer (and it's correct!), but it's not immediately obvious what that entails.
In general, back-end software informs front-end software, and front-end software informs human users.
What this means is that your back-end should be sending error information meant for a program to parse, and your front-end should interpret and transform that into language and user interface for people.
This is work for both parties, however. Your server should be sending enough information in easily consumable form. Let me give you an example:
{
errorCode: ERROR_INVALID_SOMETHING,
errorData: { something: 8, maxSomething: 5 }
}
Front-end code can easily interpret this and produce an adequate message for human users, such as "Sorry! Something must be lower than 5, and 8 is too high". You'll end up with something like this:
switch (response.errorCode) {
case ERROR_INVALID_SOMETHING:
...
}
This is very hard to accomplish if the server is sending unparsable strings with no standard or guarantees of stability. An egregious example:
{
error: "InvalidSomethingException at server.x:15 maxSomething=5 but something is '8'"
}
Front-end code can't work with this. It gets worse if you consider that the string can change for whatever reason, say if the error type changes.
There's a family of cases where showing raw server-side strings to the user is not only acceptable, but indispensable: when you want to send custom messages for a particular situation to software you cannot easily upgrade.
For example, you suddenly find a bug that puts users at risk, and need to do immediate maintenance. You want to send your users a message ASAP, and you can't wait for an app store to approve an update within the next 5 work days.
If your software was prepared to display custom messages for such an eventuality, this is a great time to do so -- but the data should follow a good structure too. For example:
errorCode: ERROR_CUSTOM
errorData: {
en: "We need to inform you about something right now",
es: "Necesitamos informarte de algo ya mismo"
}
Note that this follows a similar structure, and front-end code can still work with a standard.
You should sit down with your back-end team and come up with a shared agreement on how to structure errors and their metadata.
This may take work to get started, since you need definitions and possibly refactors, but can scale to very complex scenarios and you might never need to rework the code again.
Errors must be driven from scenarios, api must return right indicator to represent the true end to end state, and direct/inform user about what they need to do next or what happened in the system: generic messaging structures should be avoided in api, except for 404 or 501, 500 failure. Each logical message must have a instructional value to reduce the cognitive load.
Example: a cart item may not be returned due to invalid product id, or due to out of stock situation, or may be missing requires information in the object.. all of these scenarios must return a meaningful indicator to let frontend display informative and clear message to the user about end system state in user friendly manner.
IT teams must lead this effort and help business partners to implement right messaging verbiage. This would be impactful only if there is proper API to Front end messaging framework design is in place covering functional and non-functional scenarios.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With