reduxjs/redux-toolkit

Customise the .unwrap implementation

HHK1 opened this issue · 0 comments

HHK1 commented

Context

I'm using RTK Query, and plugging it onto an existing project.

HTTP Errors from the API are some specific subclass of Error. They may contain some extra information returned by the backend, and the specific subclass is used in the codebase to narrow down the type of error with syntax such as:

 try {
    // Do a request
 } catch (error) {
  if (error instance of AuthError) {
    // do something like log out
  } else if (error instance of ServerError) {
    // Show a 500 hundred like error
  } else if (error instance of ClientError {
   // More specific error handling
  }
}

I've written a serializeError to be able to throw a serialised version of those errors inside my queryFn used in my api endpoints definitions. (I don't use the baseQuery, but it's probably not super relevant).

I was able to write a custom unwrapResponse function that takes a query or mutation result and extract the data from it, or throw an error with the correct class instance (based on the content of the serialised error inside the result). That way I don't have to rewrite the error handling logic across the whole application.

A typical usage of a mutation that requires error handling would look like this:

  const [createTeam] = useCreateTeamMutation()

  const onSubmit = handleSubmit(async ({ name, pictureUrl }) => {
    try {
      const result = await createTeam({ name, pictureUrl })
      const team = unwrapResult(result)
      onSuccess(team)
    } catch (error) {
      const errorInfo = getErrorInfo(error) // this function checks if the error has a specific subclass
      setError(errorInfo)
    }
  })

Problem

Every time I use a query or a mutation other developers in the team must know about my custom unwrapReponse function, and if they don't they may incorrectly use the existing .unwrap function on the query / mutation result. Doing so won't raise any error, and errors thrown from that .unwrap won't be handled properly (those errors will be serialised errors, and not the expected subclass instances)

A typical bad usage of the same mutation will become:

  const [createTeam] = useCreateTeamMutation()

  const onSubmit = handleSubmit(async ({ name, pictureUrl }) => {
    try {
      const team = await createTeam({ name, pictureUrl }).unwrap()
      onSuccess(team)
    } catch (error) {
      const errorInfo = getErrorInfo(error) // Here the `getErrorInfo` will fail and will swallow the exact error that was thrown
      setError(errorInfo)
    }
  })

So my question is:

I'm wondering if there is a way to customise that .unwrap method, and pass my custom unwrapResponse implementation to avoid exposing a "bad" unwrap implementation.