Search code examples
reactjsapierror-handlingaxiosreact-final-form

Show Api errors with React final form and Axios


I'm trying to show errors coming back from my Api using React Final Form and Axios for the API calls. It seems like the Form is not reloading with the error message when I return the error within the .catch() from Axios.

As you can see with the commented out return up top, if I call it there, it shows the error in the Form properly. Though when I call it within the catch() it does not show any error.

What I want to do is return the error within the catch, when the API for example sends an 400 response.

My onSubmit is the following and axiosConfig is just an interceptor for attaching a token to the api call. I also tested it with plain axios but the behavior is the same.

  const onSubmit = async values => {
    //return { [FORM_ERROR]: "Login Failed" };
    axiosConfig.put('/api/v1/user/change-password/' + userPk, values, {
      'headers': { 'Authorization': auth }
    }).then( result => {
      if (result.status === 200) {
        setChanged(true);
      } 
    }).catch((error) => {
      console.log(error)
      return { [FORM_ERROR]: "Login Failed" };
    });
  };

My form looks like this.

  return (
    <div style={{ padding: 16, margin: 'auto', maxWidth: 650 }}>
      <Form
        onSubmit={onSubmit}
        initialValues={{  }}
        validate={validate}
        render={({ 
          submitError,
          handleSubmit,
          reset,
          submitting,
          pristine,
          values 
          }) => (
          <form onSubmit={handleSubmit} noValidate>
            <Paper style={{ padding: 16 }}>
              <Typography variant="h5" align="center" component="h2" gutterBottom>
                Passwort Ändern
              </Typography>
              {console.log(submitError)}

              <div>
                <Grid container alignItems="center" justify="center" spacing={4}>

                  <Grid item>
                    <Field 
                      fullWidth
                      required
                      margin="normal"
                      variant="outlined"
                      component={TextField}
                      name="old_password"
                      label="Altes Passwort"
                      type="password"
                    />                  
                    <Field 
                      fullWidth
                      required
                      margin="normal"
                      variant="outlined"
                      type="password"
                      name="new_password"
                      component={TextField}
                      label="Neues Password"
                    />                  
                    <Field 
                      fullWidth
                      required
                      margin="normal"
                      variant="outlined"
                      type="password"
                      name="new_password2"
                      component={TextField}
                      label="Neues Password Wiederholen"
                    />                  
                  </Grid>

                </Grid>
              </div>
              <div>
                {submitError && <div className="error">{submitError}</div>}
                <Grid container alignItems="flex-start" justify="space-between" spacing={4}>

                  <Grid item xs container spacing={4}>
                    <Grid item style={{ marginTop: 16 }}>
                      <Button
                        component={ Link }
                        to="/account/information"
                        type="button"
                        variant="contained"
                      >
                        Zurück
                      </Button>
                    </Grid>
                    <Grid item style={{ marginTop: 16 }}>
                      <Button
                        variant="contained"
                        color="primary"
                        type="submit"
                      >
                        Speichern
                      </Button>
                    </Grid>
                  </Grid>


                </Grid>
              </div>
            </Paper>
          </form>
        )}
      />
    </div>
  );

Solution

  • Try using the async/await syntax.

    There also might be a case that your error block is not being called in the first place and the control is still going in the success callback. So you also might want to place an else condition in there to return an error if the status code is not 200.

    Something like this:

    const onSubmit = async values => {
      try {
        const result = await axiosConfig.put('/api/v1/user/change-password/' + userPk, values, {
          'headers': {
            'Authorization': auth
          }
        });
    
        if (result.status === 200) {
          setChanged(true);
        } else {
          // You Might also want to try this!
          return {
            [FORM_ERROR]: "Login Failed"
          };
        }
      } catch (error) {
        console.log(error)
        return {
          [FORM_ERROR]: "Login Failed"
        };
      }
    };