Document clients `interceptors.error` and the response `error` field
Description
Hello again,
In trying to figure out what exactly is contained in the error field on invalid response I've read the code and noticed that besides the request and response interceptors there is another one, the error interceptor.
That is a great feature I wish I would've known before :)
The error interceptor is currently not documented in the docs of the website, so I was wondering if it is more of a private API or whether we can document that interceptor, too.
Oh, and while at it we might want to document that error returns either a JSON parsed value or - if not parseable - the body string. I was unable to find that in the docs, too.
Good callout @LinuCC. It's not private, I just never thought to document it because I'm not sure I have it across all clients. Which should be done if I'm not doing it. The fact the error type is not consistent might need to be addressed too. Again, didn't spend too much time thinking about it! What do you use it for?
We map the error to our own custom Api Error extending Error. It is nice to, for example, differentiate between unauthorized errors and other ones to automatically handle authentication problems higher up.
Are you able to share code sample here?
Sure, its pretty simple:
function myMapError(error: unknown, response: Response, request: Request, _options: Options): unknown | Promise<unknown> {
return MyApiError.fromResponse({ error, response, request });
}
// During Setup of client
myClient.interceptors.error.use(myMapError);
// Example of how we parse it
export class MyApiError extends Error {
apiError: MyApiErrorDetails;
protected constructor(
args: {
apiError: MyApiErrorDetails;
message: string
}
) {
// ...
}
static fromResponse<TError = unknown>(
res: {
data?: unknown;
error: TError;
request: Request;
response: Response;
}
) {
if (res.response.headers.get('content-type')?.includes('application/problem+json')) {
const problemJson = jsonProblemsSchema.safeParse(res.error);
if (problemJson.success) {
return new MyApiError({
apiError: {
type: 'my-api-error-details-problem-json',
statusCode: res.response.status,
problemJson: problemJson.data,
},
message: 'MyApiError: API error with Problem JSON',
});
}
}
return new MyApiError(
// With some other mapping...
);
}
}
We don't trust the backend to always correctly handle problem-json, so we use zod to parse it first and ensure that the response is what we expect.
That makes sense. Are you using it through validator? RE this interceptor, I am always surprised in how many ways people use this package 😀
Nope, the API's responses are too big and too fast to run Zod over them - we just validate the json problems with zod, since error handling is hard™️ and responses of the API are well typed.
RE this interceptor, I am always surprised in how many ways people use this package 😀
It does have a lot of fancy tooling to make it do cool stuff ;)
Would you be open to adding documentation for the interceptor?
Sure can do once I got a quiet minute!
function myMapError(error: unknown, response: Response, request: Request, _options: Options): unknown | Promise
{ return MyApiError.fromResponse({ error, response, request }); } // During Setup of client myClient.interceptors.error.use(myMapError);
could be that with client-fetch error doesn't work? I copy your code and if I turn of my backend, interceptor error doesn't do anything.