| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- import { describe, expect, test } from "bun:test"
- import { OpenApi } from "effect/unstable/httpapi"
- import { PublicApi } from "../../src/server/routes/instance/httpapi/public"
- type Method = "get" | "post" | "put" | "delete" | "patch"
- type OpenApiSchema = { readonly $ref?: string }
- type OpenApiResponse = {
- readonly description?: string
- readonly content?: Record<string, { readonly schema?: OpenApiSchema }>
- }
- type OpenApiOperation = {
- readonly responses?: Record<string, OpenApiResponse>
- readonly security?: unknown
- }
- type OpenApiPathItem = Partial<Record<Method, OpenApiOperation>>
- type OpenApiSpec = { readonly paths: Record<string, OpenApiPathItem> }
- const methods = ["get", "post", "put", "delete", "patch"] as const
- const allowedV2BuiltInEndpointErrors: string[] = []
- function v2Operations(spec: OpenApiSpec) {
- return Object.entries(spec.paths).flatMap(([path, item]) =>
- path.startsWith("/api/")
- ? methods.flatMap((method) => {
- const operation = item[method]
- return operation ? [{ method, path, operation }] : []
- })
- : [],
- )
- }
- function responseRef(response: OpenApiResponse | undefined) {
- return response?.content?.["application/json"]?.schema?.$ref
- }
- function componentName(ref: string) {
- return ref.replace("#/components/schemas/", "")
- }
- function isBuiltInEndpointError(name: string) {
- return name.startsWith("EffectHttpApiError") || name.startsWith("effect_HttpApiError_")
- }
- describe("PublicApi OpenAPI v2 errors", () => {
- test("preserves /api auth responses", () => {
- const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
- for (const route of v2Operations(spec)) {
- expect(route.operation.responses?.["401"], `${route.method.toUpperCase()} ${route.path}`).toBeDefined()
- expect(route.operation.security, `${route.method.toUpperCase()} ${route.path}`).toEqual([])
- }
- })
- test("does not rewrite /api endpoint errors to legacy error components", () => {
- const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
- const refs = v2Operations(spec)
- .flatMap((route) =>
- Object.entries(route.operation.responses ?? {}).flatMap(([status, response]) => {
- const ref = responseRef(response)
- return ref ? [`${route.method.toUpperCase()} ${route.path} ${status} ${componentName(ref)}`] : []
- }),
- )
- .filter((entry) => entry.endsWith(" BadRequestError") || entry.endsWith(" NotFoundError"))
- expect(refs).toEqual([])
- })
- test("new /api endpoint errors cannot use built-in components without an explicit allowlist", () => {
- const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
- const builtInEndpointErrors = v2Operations(spec)
- .flatMap((route) =>
- Object.entries(route.operation.responses ?? {}).flatMap(([status, response]) => {
- if (status === "401") return []
- const ref = responseRef(response)
- if (!ref) return []
- const name = componentName(ref)
- return isBuiltInEndpointError(name) ? [`${route.method.toUpperCase()} ${route.path} ${status} ${name}`] : []
- }),
- )
- .sort()
- expect(builtInEndpointErrors).toEqual(allowedV2BuiltInEndpointErrors)
- })
- test("documents v2 provider and model catalog errors", () => {
- const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
- expect(componentName(responseRef(spec.paths["/api/provider"]?.get?.responses?.["503"]) ?? "")).toBe(
- "ServiceUnavailableError",
- )
- expect(componentName(responseRef(spec.paths["/api/model"]?.get?.responses?.["503"]) ?? "")).toBe(
- "ServiceUnavailableError",
- )
- expect(componentName(responseRef(spec.paths["/api/provider/{providerID}"]?.get?.responses?.["404"]) ?? "")).toBe(
- "ProviderNotFoundError",
- )
- expect(componentName(responseRef(spec.paths["/api/provider/{providerID}"]?.get?.responses?.["503"]) ?? "")).toBe(
- "ServiceUnavailableError",
- )
- })
- })
|