Description
openedon May 6, 2024
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.