Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response is undefined in the event of an error #384

Closed
thclark opened this issue Mar 11, 2021 · 3 comments
Closed

Response is undefined in the event of an error #384

thclark opened this issue Mar 11, 2021 · 3 comments

Comments

@thclark
Copy link

thclark commented Mar 11, 2021

Feature Request

In the event of an error, the response and data objects reurned by useAxios are undefined. I think this is intended behaviour, because the docs refer to response explicitly as the "Success response object".

I guess that makes this a feature request for the response object to contain the response irrespective of success state.

Without the full response in the event of an error, it's impossible to handle the error correctly (or differently according to what the error was).

Use Case

I built a FormHandler with axios-hooks that enables me to simply wrap any visual form component with a handler. However, unless there's something I can't see, it's not able to use axios-hooks because the response value only updates on success, not on failure... so I'm not able to display field errors returned from the API in the form.

Example

I submit some (invalid) data using POST request with useAxios:

{"firstName": "Tom", "lastName": "Clark"}

From Chrome devtools, I can see a 400 response whose data looks like:

{"firstName":["That's a terrible first name."],"lastName":["I don't like your last name either."]}

(I know. It's a test.)

useAxios Setup

In the following setup of useAxios, const apiErrors = error ? response.data : {} always produces undefined.

import React from 'react'
import PropTypes from 'prop-types'
import useAxios, { configure } from 'axios-hooks'
import Axios from 'axios'

// Configure an axios instance to submit form data
// Exported to allow creation of mock axios calls in storybooks
export const axios = Axios.create()

configure({ axios })

/**
 * A Form Handler service that renders a react component containing a form, handling submission to the
 * Google Cloud Functions endpoint.
 *
 * This handler could be implemented many ways... e.g. as a HOC or even rewritten as a hook 'useFormHandler' to provide
 * `[handleSubmit, apiErrors, submitting]` directly in the form component.
 *
 * I've chosen to do it as a component for... no real reason, other than "having a parent/container component
 * taking care of data fetching/updating" is a pretty common pattern in react.
 *
 */
function FormHandler({ FormComponent, endpoint, ...rest }) {
  const [{ data, loading, error, response }, execute] = useAxios(
    {
      url: `https://europe-west1-myprojectid.cloudfunctions.net${endpoint}`,
      method: 'POST',
    },
    { manual: true } // Prevents request on initial render
  )

  function handleSubmit(data) {
    execute({ data })
  }

  console.log('THIS IS ALWAYS UNDEFINED IF THERE IS AN ERROR', response?.data)
  const apiErrors = error ? { ...response.data} : {}
  return (
    <FormComponent
      {...rest}
      submitting={loading}
      apiErrors={apiErrors}
      onSubmit={handleSubmit}
    />
  )
}

FormHandler.defaultProps = {
  endpoint: '/contact',
}

FormHandler.propTypes = {
  /**
   * The endpoint to POST the form data to, eg '/contact'
   */
  endpoint: PropTypes.oneOf(['/contact', '/subscribe']).isRequired,
  /**
   * The form component to be rendered within the handler
   */
  FormComponent: PropTypes.object.isRequired,
}

export default FormHandler
@simoneb
Copy link
Owner

simoneb commented Mar 11, 2021

In the case of an error, the error property of the hook return value is populated with the error full response, see:

[action.error ? 'error' : 'response']: action.payload

Does this do what you need?

@thclark
Copy link
Author

thclark commented Mar 12, 2021

Hmm, yes, this appears to do exactly what I need. That's so obvious that I had already tried it when I submitted this issue and "error" was simply a printed error summary, not a response object. So maybe this is an upstream issue. I'll investigate and report back.

So yep, this is an upstream (or cross-stream) issue. The error thrown by axios-mock-adapter, which I use to test these things, isn't resolved into an actual error object even if you give it an error code - turns out you have to use a custom callback that manually attaches the data, then Promise.reject()s with the error. That's documented in an open issue here.

So it's a case of the mock adapter being far lower level than I expected.

Apologies for the poke, @simoneb, and thanks for the help🥇

@thclark thclark closed this as completed Mar 12, 2021
@simoneb
Copy link
Owner

simoneb commented Mar 12, 2021

No problem, glad you found a solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants