mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-22 02:56:28 -05:00
Merge branch 'epic/v5' into feat/survey-scheduling
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { V3ApiError, getV3ApiErrorMessage, parseV3ApiError } from "@/modules/api/lib/v3-client";
|
||||
|
||||
describe("parseV3ApiError", () => {
|
||||
test("parses RFC 9457 error responses into a typed V3ApiError", async () => {
|
||||
const response = new Response(
|
||||
JSON.stringify({
|
||||
title: "Forbidden",
|
||||
status: 403,
|
||||
detail: "You are not authorized to access this resource",
|
||||
code: "forbidden",
|
||||
requestId: "req_1",
|
||||
invalid_params: [{ name: "surveyId", reason: "Invalid id" }],
|
||||
}),
|
||||
{
|
||||
status: 403,
|
||||
headers: {
|
||||
"Content-Type": "application/problem+json",
|
||||
"X-Request-Id": "req_1",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const error = await parseV3ApiError(response);
|
||||
|
||||
expect(error).toBeInstanceOf(V3ApiError);
|
||||
expect(error.status).toBe(403);
|
||||
expect(error.detail).toBe("You are not authorized to access this resource");
|
||||
expect(error.code).toBe("forbidden");
|
||||
expect(error.requestId).toBe("req_1");
|
||||
expect(error.invalid_params).toEqual([{ name: "surveyId", reason: "Invalid id" }]);
|
||||
});
|
||||
|
||||
test("falls back to a provided fallback message", () => {
|
||||
expect(getV3ApiErrorMessage(new Error("boom"), "fallback")).toBe("boom");
|
||||
expect(getV3ApiErrorMessage("bad", "fallback")).toBe("fallback");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
export type TV3InvalidParam = {
|
||||
name: string;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
type TV3ProblemBody = {
|
||||
status?: number;
|
||||
detail?: string;
|
||||
code?: string;
|
||||
requestId?: string;
|
||||
invalid_params?: TV3InvalidParam[];
|
||||
};
|
||||
|
||||
export class V3ApiError extends Error {
|
||||
status: number;
|
||||
code?: string;
|
||||
requestId?: string;
|
||||
invalid_params?: TV3InvalidParam[];
|
||||
|
||||
constructor({
|
||||
status,
|
||||
detail,
|
||||
code,
|
||||
requestId,
|
||||
invalid_params,
|
||||
}: {
|
||||
status: number;
|
||||
detail: string;
|
||||
code?: string;
|
||||
requestId?: string;
|
||||
invalid_params?: TV3InvalidParam[];
|
||||
}) {
|
||||
super(detail);
|
||||
this.name = "V3ApiError";
|
||||
this.status = status;
|
||||
this.code = code;
|
||||
this.requestId = requestId;
|
||||
this.invalid_params = invalid_params;
|
||||
}
|
||||
|
||||
get detail(): string {
|
||||
return this.message;
|
||||
}
|
||||
}
|
||||
|
||||
export function getV3ApiErrorMessage(error: unknown, fallbackMessage: string): string {
|
||||
if (error instanceof V3ApiError) {
|
||||
return error.detail;
|
||||
}
|
||||
|
||||
if (error instanceof Error && error.message) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
return fallbackMessage;
|
||||
}
|
||||
|
||||
export async function parseV3ApiError(response: Response): Promise<V3ApiError> {
|
||||
let problemBody: TV3ProblemBody | undefined;
|
||||
|
||||
try {
|
||||
problemBody = (await response.json()) as TV3ProblemBody;
|
||||
} catch {
|
||||
problemBody = undefined;
|
||||
}
|
||||
|
||||
return new V3ApiError({
|
||||
status: problemBody?.status ?? response.status,
|
||||
detail: problemBody?.detail ?? response.statusText ?? "An unexpected error occurred.",
|
||||
code: problemBody?.code,
|
||||
requestId: problemBody?.requestId ?? response.headers.get("X-Request-Id") ?? undefined,
|
||||
invalid_params: problemBody?.invalid_params,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user