Handle Errors inside of Forms being posted to a custom API
Hey everyone!
We're using Refine to such a great extend and I'm very thankful for all the work that has been put into Refine so far!
Right now we're facing a situation, where we have a custom API that we are using to create workflows for users. Whenever we encounter errors inside the custom API, I'm wondering how to handle those respectively inside of the frontend. Here we have three different types of errors, that I'd like to handle. Maybe there is a solution to all three situations in Refine, but I'm missing a concept?
1. Handle global errors ✅
This one is pretty basic, and can be handled through a interceptor inside of Axios. Basically we encounter >500 errors inside of the API that might point to a network failure or general availability. I'm showing a toast right now if anything goes wrong on the server side.
2. Handle general form errors ❓
So this one is the first I'm struggling with, we basically check for general sanity of the form somebody posted. Since we're editing DTOs inside of our backend, say there is a check, that a certain combination of entries cannot be done, i.e. "This combination of attributes is not allowed". How would I handle such a case, what would the optimal JSON response from the API look like to scope the error to the form and show it inside of refine? I want to have a uniform solution, so that we don't have to build this again and again. Suggestions highly welcome!
3. Handle scoped form field errors ❓
This one is the second one I'm struggling with, since we have a collection of fields i.e. "id, name, zip, city", the server side could be checking something like "does the zip and the city match?" and if they don't match I want to show an error on the city field (just as an example) like "your city does not match the zip you entered". How would I pass the error to the form, so that (in our case) Antd would be able to work with that? Maybe it's too custom, but maybe that's something you figured out already 🙂
Cheers!
21 Replies
Hi @bastianwegge. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
Hello!
Refine provides a way to handle all three types of errors you mentioned. Let's go through them one by one:
1. Handle global errors: As you mentioned, you can handle global errors using an interceptor in Axios. This is also mentioned in the Refine documentation (https://refine.dev/docs/api-reference/core/providers/data-provider/). You can create a custom error with the
HttpError
type from Refine and reject the promise with this error.
2. Handle general form errors: Refine supports server-side validation out-of-the-box for all supported UI frameworks. To handle server-side validation errors, you need to return a rejected promise with the errors
field from the dataProvider
. The errors
field can be a string
, string[]
, boolean
, or an object with key
and message
fields. If the field is an object, the key
field will be used as a translation key. If the key
is not found in the translation, the message
field will be displayed. Here is an example of how to structure the error:
You can find more information about this in the Refine documentation (https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/).
3. Handle scoped form field errors: The errors
field in the HttpError
type can be used to assign errors to specific form fields. When the dataProvider
returns a rejected promise with the errors
field, the useForm
hook will assign the errors to the respective form fields. Here is an example of how to structure the error:
In this case, the error message "Zip and city do not match" will be displayed in the zip
field. You can find more information about this in the Refine documentation (https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/).
I hope this helps! Let me know if you have any other questions.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@317433576721219584> kapa.ai is still learning and improving, please let us know how it did by reacting below
foreign-sapphireOP•17mo ago
In point 2 you were mentioning the errors field inside of the HttpError. But I don't see something like a general "form error". Say you want to tell the user that "saving didn't work" but you don't want to show a toast that hides after X seconds but rather something like a permanent message on top of the form. Is there something like this in Refine?
@kapa.ai can you take another shot at the question I asked?
Let me check the knowledge base for you. One moment! :books:
----------------------
Hello!
I'm glad to hear that you're finding Refine useful! Let's address your questions about error handling:
1. Handle global errors: You're correct that Axios interceptors can be used for global error handling. Refine also provides the
onError
method in the authProvider
for handling error responses from the API. You can create your own business logic to handle the error such as refreshing the token, logging out the user, etc. Here's the relevant documentation (https://refine.dev/docs/api-reference/core/providers/auth-provider/).
2. Handle general form errors: For handling general form errors, Refine supports server-side validation out-of-the-box. You need to return a rejected promise with the errors
field from the dataProvider
. The errors
field can be a string
, string**]
, boolean
, or an object with key
and message
fields. If the field is an object, the key
field will be used as a translation key. If the key
is not found in the translation, the message
field will be displayed. [Here's the relevant documentation (https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/).
3. Handle scoped form field errors: For handling scoped form field errors, you can use the same errors
field in the HttpError
type. When the dataProvider
returns a rejected promise with the errors
field, the useForm
hook will assign the errors to the respective form fields. For example, if you have an error related to the city
field, you can structure your error like this:
In this case, the error message "Your city does not match the zip you entered" will be displayed in the city
field. Here's the relevant documentation** (https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/).
I hope this helps! Let me know if you have any other questions.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@317433576721219584> kapa.ai is still learning and improving, please let us know how it did by reacting below
foreign-sapphireOP•17mo ago
Oh this is so great! Works like a charm @core you guys are awesome!!!!!
sensitive-blue•17mo ago
hello @bastianwegge. thanks 🥲
also thanks to kappa ai 😀
foreign-sapphireOP•17mo ago
@kapa.ai Is there a way to use a custom field or custom ErrorList to show custom errors above the fields of the form? I want to show general errors for the form.
Let me check the knowledge base for you. One moment! :books:
----------------------
Yes, you can handle general form errors in Refine by using the
errors
field in the HttpError
type. When the dataProvider
returns a rejected promise with the errors
field, the useForm
hook will assign the errors to the respective form fields.
For example, if you have a general error for the form, you can structure your error like this:
In this case, the error message "This combination of attributes is not allowed" will be displayed for the form.
However, displaying this error message above the form fields would require custom implementation. You would need to access the errors
state from the useForm
hook and display the error message in your desired location. Here is an example of how you can access the errors
state:
You can find more information about this in the Refine documentation (https://refine.dev/docs/advanced-tutorials/forms/server-side-form-validation/).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@317433576721219584> kapa.ai is still learning and improving, please let us know how it did by reacting below
foreign-sapphireOP•17mo ago
@kapa.ai form.mutationResult does not exist
Let me check the knowledge base for you. One moment! :books:
----------------------
I apologize for the confusion. You're correct, the
form.mutationResult
does not exist. The correct way to access the mutationResult
is directly from the useForm
hook. Here's how you can do it:
In this case, mutationResult.error?.errors
will give you the errors returned from the dataProvider
. You can then display these errors above your form fields as per your requirements.
You can find more information about this in the Refine documentation (https://refine.dev/docs/api-reference/core/hooks/useForm/).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@317433576721219584> kapa.ai is still learning and improving, please let us know how it did by reacting below
foreign-sapphireOP•17mo ago
@alicanerdurmaz is there maybe a nicer way to access a specific Error from the map of errors to show above my fields in my form?
sensitive-blue•17mo ago
What exactly do you want to do, can you explain me more please?
foreign-sapphireOP•17mo ago
Yes of course!
Say I have a form like this:
I want to be able to just put a field on top of my form to display "general" messages for the form, like
my-special-error
but I don't know where to get the errors from basically. When I'm using a toast (or any other notification method), this will disappear in a couple of seconds. I want to have a persistent method of showing an error inside of my form that is not directly related to a Input, but rather define a "custom-field-name" that can be used by the backend to provide more information on an error-state.
lol I just solved this by trying to explain what I want to do 😄 🤷♂️
You can actually use a Form.Item with an ErrorList, but remove the errors={errors}
Well thank you I guess 😄 🙏sensitive-blue•17mo ago
oh. thanks for the clear explanation. I'm glad the problem was solved 🙌🏻
foreign-sapphireOP•17mo ago
It's not the prettiest error, but I guess I can solve that with some Ant.D Styling:
sensitive-blue•17mo ago
yes its require custom css or component :/
foreign-sapphireOP•17mo ago
Just for completeness sake, this was my solution:
As the ErrorList on top of the form is kind of ugly, I converted it into Alerts.
foreign-sapphireOP•17mo ago
AND you have to have a
<FormItem name={props.namePath} hidden />
for the field to be available through getFieldsError()
, otherwise the error won't show up.