openapi-ts icon indicating copy to clipboard operation
openapi-ts copied to clipboard

Document clients `interceptors.error` and the response `error` field

Open LinuCC opened this issue 11 months ago • 10 comments

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.

LinuCC avatar Mar 04 '25 09:03 LinuCC

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?

mrlubos avatar Mar 25 '25 18:03 mrlubos

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.

LinuCC avatar Mar 26 '25 08:03 LinuCC

Are you able to share code sample here?

mrlubos avatar Mar 26 '25 09:03 mrlubos

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.

LinuCC avatar Mar 26 '25 09:03 LinuCC

That makes sense. Are you using it through validator? RE this interceptor, I am always surprised in how many ways people use this package 😀

mrlubos avatar Mar 26 '25 09:03 mrlubos

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 ;)

LinuCC avatar Mar 26 '25 09:03 LinuCC

Would you be open to adding documentation for the interceptor?

mrlubos avatar Mar 26 '25 09:03 mrlubos

Sure can do once I got a quiet minute!

LinuCC avatar Mar 26 '25 09:03 LinuCC

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.

goltra avatar May 07 '25 12:05 goltra