forked from imbytecat/fullstack-starter
- 添加 @orpc/openapi 依赖以支持 OpenAPI 生成和集成。 - 配置 OpenAPI 文档生成与请求拦截,集成 Zod 验证错误处理并支持 Bearer 认证。 - 添加 @orpc/openapi 依赖并更新版本号至 1.13.4 - 添加 @orpc/openapi 依赖以支持 OpenAPI 生成功能。
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
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'
|
|
|
|
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 })
|
|
},
|
|
},
|
|
},
|
|
})
|