Enhance ApiClient with error handling and flexible HTTP methods. Introduce ApiError class for better error management, normalize base URL resolution from environment variables, and update createClient function to support custom error handling and authorization middleware.
This commit is contained in:
parent
dcf32c1d06
commit
06009bd2d5
@ -1,46 +1,83 @@
|
|||||||
import createOpenApiClient from "openapi-fetch";
|
import createOpenApiClient from "openapi-fetch";
|
||||||
import type { paths } from "../__generated__/types";
|
import type { paths } from "../__generated__/types";
|
||||||
|
|
||||||
|
export class ApiError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: string,
|
||||||
|
public readonly response: Response,
|
||||||
|
public readonly body?: unknown
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = "ApiError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type ApiClient = ReturnType<typeof createOpenApiClient<paths>>;
|
export type ApiClient = ReturnType<typeof createOpenApiClient<paths>>;
|
||||||
|
|
||||||
export type AuthHeaderResolver = () => string | undefined;
|
export type AuthHeaderResolver = () => string | undefined;
|
||||||
|
|
||||||
export interface CreateClientOptions {
|
export interface CreateClientOptions {
|
||||||
getAuthHeader?: AuthHeaderResolver;
|
getAuthHeader?: AuthHeaderResolver;
|
||||||
|
handleError?: (response: Response) => void | Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function defaultHandleError(response: Response) {
|
||||||
|
if (response.ok) return;
|
||||||
|
|
||||||
|
let body: unknown;
|
||||||
|
let message = response.statusText || `Request failed with status ${response.status}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cloned = response.clone();
|
||||||
|
const contentType = cloned.headers.get("content-type");
|
||||||
|
if (contentType?.includes("application/json")) {
|
||||||
|
body = await cloned.json();
|
||||||
|
if (body && typeof body === "object" && "message" in body && typeof (body as any).message === "string") {
|
||||||
|
message = (body as any).message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const text = await cloned.text();
|
||||||
|
if (text) {
|
||||||
|
body = text;
|
||||||
|
message = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore body parse errors; fall back to status text
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApiError(message, response, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createClient(
|
export function createClient(
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
options: CreateClientOptions = {}
|
options: CreateClientOptions = {}
|
||||||
): ApiClient {
|
): ApiClient {
|
||||||
const client = createOpenApiClient<paths>({
|
const client = createOpenApiClient<paths>({ baseUrl });
|
||||||
baseUrl,
|
|
||||||
throwOnError: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const handleError = options.handleError ?? defaultHandleError;
|
||||||
|
|
||||||
if (typeof client.use === "function" && options.getAuthHeader) {
|
if (typeof client.use === "function") {
|
||||||
const resolveAuthHeader = options.getAuthHeader;
|
const resolveAuthHeader = options.getAuthHeader;
|
||||||
|
|
||||||
client.use({
|
client.use({
|
||||||
onRequest({ request }: { request: Request }) {
|
onRequest({ request }) {
|
||||||
if (!request || typeof request.headers?.has !== "function") {
|
if (!resolveAuthHeader) return;
|
||||||
return;
|
if (!request || typeof request.headers?.has !== "function") return;
|
||||||
}
|
if (request.headers.has("Authorization")) return;
|
||||||
|
|
||||||
if (request.headers.has("Authorization")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerValue = resolveAuthHeader();
|
const headerValue = resolveAuthHeader();
|
||||||
if (!headerValue) {
|
if (!headerValue) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.headers.set("Authorization", headerValue);
|
request.headers.set("Authorization", headerValue);
|
||||||
},
|
},
|
||||||
|
async onResponse({ response }) {
|
||||||
|
await handleError(response);
|
||||||
|
},
|
||||||
} as never);
|
} as never);
|
||||||
}
|
}
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type { paths };
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user