From dede23ead9a7a2467c79e71645a0fe129db96316 Mon Sep 17 00:00:00 2001 From: imbytecat Date: Thu, 22 Jan 2026 16:43:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20OpenAPI=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=8E=E9=9B=86=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 @orpc/openapi 依赖以支持 OpenAPI 生成和集成。 - 配置 OpenAPI 文档生成与请求拦截,集成 Zod 验证错误处理并支持 Bearer 认证。 - 添加 @orpc/openapi 依赖并更新版本号至 1.13.4 - 添加 @orpc/openapi 依赖以支持 OpenAPI 生成功能。 --- apps/server/package.json | 1 + apps/server/src/routes/api/$.ts | 85 ++++++++++++++++++++++++++++++++- bun.lock | 2 + package.json | 1 + 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/apps/server/package.json b/apps/server/package.json index de9180e..de16a14 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -17,6 +17,7 @@ "dependencies": { "@orpc/client": "catalog:", "@orpc/contract": "catalog:", + "@orpc/openapi": "catalog:", "@orpc/server": "catalog:", "@orpc/tanstack-query": "catalog:", "@orpc/zod": "catalog:", diff --git a/apps/server/src/routes/api/$.ts b/apps/server/src/routes/api/$.ts index 0940eeb..5493b54 100644 --- a/apps/server/src/routes/api/$.ts +++ b/apps/server/src/routes/api/$.ts @@ -1,3 +1,86 @@ +import { OpenAPIHandler } from '@orpc/openapi/fetch' +import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins' +import { ORPCError, onError, ValidationError } from '@orpc/server' +import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4' import { createFileRoute } from '@tanstack/react-router' +import { z } from 'zod' +import { name, version } from '#server/../package.json' +import { router } from '@/server/api/routers' -export const Route = createFileRoute('/api/$')({}) +const handler = new OpenAPIHandler(router, { + plugins: [ + new OpenAPIReferencePlugin({ + docsProvider: 'scalar', + schemaConverters: [new ZodToJsonSchemaConverter()], + specGenerateOptions: { + info: { + title: name, + version, + }, + components: { + securitySchemes: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + }, + }, + }, + }, + docsPath: '/docs', + specPath: '/spec.json', + }), + ], + interceptors: [ + onError((error) => { + console.error(error) + }), + ], + clientInterceptors: [ + onError((error) => { + if ( + error instanceof ORPCError && + error.code === 'BAD_REQUEST' && + error.cause instanceof ValidationError + ) { + // If you only use Zod you can safely cast to ZodIssue[] + const zodError = new z.ZodError( + error.cause.issues as z.core.$ZodIssue[], + ) + + throw new ORPCError('INPUT_VALIDATION_FAILED', { + status: 422, + message: z.prettifyError(zodError), + data: z.flattenError(zodError), + cause: error.cause, + }) + } + + if ( + error instanceof ORPCError && + error.code === 'INTERNAL_SERVER_ERROR' && + error.cause instanceof ValidationError + ) { + throw new ORPCError('OUTPUT_VALIDATION_FAILED', { + cause: error.cause, + }) + } + }), + ], +}) + +export const Route = createFileRoute('/api/$')({ + server: { + handlers: { + ANY: async ({ request }) => { + const { response } = await handler.handle(request, { + prefix: '/api', + context: { + headers: request.headers, + }, + }) + + return response ?? new Response('Not Found', { status: 404 }) + }, + }, + }, +}) diff --git a/bun.lock b/bun.lock index e97f4ed..3a547bd 100644 --- a/bun.lock +++ b/bun.lock @@ -27,6 +27,7 @@ "dependencies": { "@orpc/client": "catalog:", "@orpc/contract": "catalog:", + "@orpc/openapi": "catalog:", "@orpc/server": "catalog:", "@orpc/tanstack-query": "catalog:", "@orpc/zod": "catalog:", @@ -76,6 +77,7 @@ "@effect/schema": "^0.75.5", "@orpc/client": "^1.13.4", "@orpc/contract": "^1.13.4", + "@orpc/openapi": "^1.13.4", "@orpc/server": "^1.13.4", "@orpc/tanstack-query": "^1.13.4", "@orpc/zod": "^1.13.4", diff --git a/package.json b/package.json index dee98da..b32ffaf 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@effect/schema": "^0.75.5", "@orpc/client": "^1.13.4", "@orpc/contract": "^1.13.4", + "@orpc/openapi": "^1.13.4", "@orpc/server": "^1.13.4", "@orpc/tanstack-query": "^1.13.4", "@orpc/zod": "^1.13.4",