Show API error in notification
Asked Answered
C

2

10

I'm missing something basic in the docs. When I get an API validation error, I'm returning a status code and message. It appears that React-Admin is translating the status code to a generic HTTP error code.

My error response.

{"error":
    {"statusCode":422,
    "name":"Error",
    "message":"User with same first and last name already on team."}
}

When my API response with that response, I'm seeing "Unprocessable Entity" in the notification box. I'm using SimpleForm.

I know the status code is being recognized because I've changed the 422 and it shows the corresponding HTTP error description.

In the docs it says to throw and error in your data provider. I've moved that the Simple Rest data provider into my project and have tried throwing errors are various places, but nothing changes on the client.

https://marmelab.com/react-admin/DataProviders.html#error-format

If you have customized error from your API, I'd appreciated any hints you can give. Thx.

Chronon answered 24/8, 2018 at 19:7 Comment(2)
You're right, it can be frustrating and it is not documented as is. Mind you fill an issue with your proposal to improve the default error handling behavior? Thank you very much! github.com/marmelab/react-admin/issues/…Kenna
I was hoping I was just missing something. It seems to say in the docs the if an error reponse has a {error: {name: 'xxxx}} field in the response and raised as an error in the data provider that is would be shown. I'd be happy to add that to the project docs if someone else can provide a working example.Chronon
K
11

Here is the actual error processing:

  1. When a fetch is triggered (usually coming from the data provider), if an error happen, it is caught and transformed into an HttpError and re-thrown (source)
  2. In the process, the HTTP Error message becomes either the json.message or the response statusText. It's here that a 422 HTTP Error becomes Unprocessable Entity (source)
  3. Then the error is caught again at a higher level to be transformed into a redux action. (source)
  4. Finally, the error is transformed into a notification containing the error message.

So, in order to customize your error message, you can easily do that from your custom provider by catching the error in the first place, customizing the error message, and send it again:

const dataProvider = (type, resource, params) => new Promise((resolve, reject) => {
    if (type === 'GET_LIST' && resource === 'posts') {
        return fetch(...args)
            .then(res => res.json())
            .then(json => {
                if (json.error) {
                    // The notification will show what's in { error: "message" }
                    reject(new Error(json.error.message));
                    return;
                }

                resolve(json);
            });
    }

    // ...
});
Kenna answered 27/8, 2018 at 17:3 Comment(3)
This is a really excellent response and it help to explain how errors are handled. Unfortunately, that isn't my problem. I'm not trying to create a custom error message from within react-admin. I just want to show an API error message, which is how I understand it's supposed to work. In my original question, I showed my response json. I want error.message ("User with same first and last name already on team.") to be shown in the notification and not "Unprocessable Entity". I'm obviously missing something simple. I believe my error json is correct since it's picking up statusCode.Chronon
Hi, I updated my code so that the notification can be customised by the API. Does this is a better answer to your question ?Kenna
Awesome! Much appreciated. Trying now.Chronon
H
0

in Backend, I structure the response as

res.json({status:400,message:"Email Address is invalid!"})

In Client side, modify the convertHTTPResponse in dataprovider as:

const convertHTTPResponse = (response, type, resource, params) => {
    const { headers, json } = response;
    switch (type) {
        case GET_LIST:
        case GET_MANY_REFERENCE:
            if(json.status === 200){
                if (!headers.has('content-range')) {
                    throw new Error('The Content-Range header is missing in the HTTP Response.);
                }
                return {
                    data: json.docs,
                    total: parseInt(
                        headers
                            .get('content-range')
                            .split('/')
                            .pop(),
                        10
                    ),
                };
            }else{
                throw new Error(json.message)
            }

        default:
            if(json.status === 200){
                return { data: json.docs };
            }else{
                throw new Error(json.message)
            }
    }
Hinson answered 16/12, 2018 at 4:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.