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

How to check the status code of a received error inside a hook?

Open B4rtware opened this issue 2 years ago • 4 comments

I am currently switching from a custom axios client to the openapi-codegen generated client. For that, I need to check the status code of the returned error. I have found an issue and a pull request which might be related, but I still wasn't able to make it work the way I wanted it to.

  • https://github.com/fabien0102/openapi-codegen/issues/61
  • https://github.com/fabien0102/openapi-codegen/pull/63#issue-1234995523

This is my schema from the /api/v1/auth/session/ endpoint. image

And this is my used code. The error was correctly extracted from the openapi schema. image

But even with a 403 status code and {"detail":"Authentication credentials were not provided."} as response body. I always get an unknown status and generic message: image It seems like I need to edit the fetcher.ts but I am unsure how. Maybe someone can point me in the right direction.

B4rtware avatar Oct 06 '22 20:10 B4rtware

Hi, @B4rtware can you share your fetcher.ts if it is not private?

needim avatar Oct 06 '22 20:10 needim

Hi, its mainly the default fetcher generated by openapi-codegen. I have tried to use the patches which were provided by https://github.com/fabien0102/openapi-codegen/pull/63#issue-1234995523 in the image but this messes with the components.ts since the signature of the fetcher is then different.

export async function cointainerFetch<
  TData,
  TError,
  TBody extends {} | undefined | null,
  THeaders extends {},
  TQueryParams extends {},
  TPathParams extends {},
>({
  url,
  method,
  body,
  headers,
  pathParams,
  queryParams,
  signal,
}: CointainerFetcherOptions<
  TBody,
  THeaders,
  TQueryParams,
  TPathParams
>): Promise<TData> {
  try {
    const response = await window.fetch(
      `${baseUrl}${resolveUrl(url, queryParams, pathParams)}`,
      {
        signal,
        method: method.toUpperCase(),
        body: body ? JSON.stringify(body) : undefined,
        headers: {
          "Content-Type": "application/json",
          ...headers,
        },
      },
    );
    if (!response.ok) {
      let error: ErrorWrapper<TError>;
      try {
        error = await response.json();
      } catch (e) {
        error = {
          status: "unknown" as const,
          payload:
            e instanceof Error ? `Unexpected error (${e.message})` : "Unexpected error",
        };
      }

      showNotification({
        title: response.statusText,
        message: JSON.stringify(error),
        color: "red"
      });

      throw error;
    }

    if (response.headers.get("content-type")?.includes("json")) {
      return await response.json();
    } else {
      // if it is not a json response, assume it is a blob and cast it to TData
      return (await response.blob()) as unknown as TData;
    }
  } catch (e) {
    throw {
      status: "unknown" as const,
      payload: e instanceof Error ? `Network error (${e.message})` : "Network error",
    };
  }
}

B4rtware avatar Oct 06 '22 20:10 B4rtware

I think I had some similar issues about that, and came up with a workaround for something like this in my project.

image

But I have to mention, it was a quick/dirty solution. So I will investigate this further.

needim avatar Oct 06 '22 21:10 needim

Thanks for pointing me in the right direction. I now have also created a workaround like so:

    [...]

      throw { ...error, status: response.status };
    }

    if (response.headers.get("content-type")?.includes("json")) {
      return await response.json();
    } else {
      // if it is not a json response, assume it is a blob and cast it to TData
      return (await response.blob()) as unknown as TData;
    }
  } catch (e) {
    throw {
      // @ts-ignore
      status: e.status ?? "unknown" as const,
      payload: e instanceof Error ? `Network error (${e.message})` : e ?? "Network error",
    };
  }
}

With simple tests now this code works:

      [...]
      onError: (error) => {
        if (error.status === 403) {
          console.log(error.payload.detail);
        }
      },

I'm still interested if this behavior is intended or not?

B4rtware avatar Oct 06 '22 22:10 B4rtware