-
Notifications
You must be signed in to change notification settings - Fork 1
Integrate OpenAPI documentation parsing functionality #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
e410630
refactor: move cookie config to .env
nonhana 733ce87
feat: open api import analyze
nonhana 3612a6e
refactor: optimize open api analyze
nonhana 7b6c34a
chore: tsdown config
nonhana 6664f82
feat: optimize open api import verification
nonhana File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator' | ||
|
|
||
| /** 冲突处理策略 */ | ||
| export enum ConflictStrategy { | ||
| /** 跳过冲突的 API */ | ||
| SKIP = 'skip', | ||
| /** 覆盖现有 API */ | ||
| OVERWRITE = 'overwrite', | ||
| /** 重命名新 API */ | ||
| RENAME = 'rename', | ||
| } | ||
|
|
||
| /** 解析 OpenAPI 文档请求 DTO(URL 或内容方式) */ | ||
| export class ParseOpenapiReqDto { | ||
| @IsOptional() | ||
| @IsString({ message: 'OpenAPI 文档内容必须是字符串' }) | ||
| content?: string | ||
|
|
||
| @IsOptional() | ||
| @IsString({ message: 'OpenAPI 文档 URL 必须是字符串' }) | ||
| url?: string | ||
nonhana marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
nonhana marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** 执行导入请求 DTO */ | ||
| export class ExecuteImportReqDto { | ||
| @IsString({ message: 'OpenAPI 文档内容必须是字符串' }) | ||
| content: string | ||
|
|
||
| @IsEnum(ConflictStrategy, { message: '冲突处理策略必须是有效的枚举值' }) | ||
| conflictStrategy: ConflictStrategy | ||
|
|
||
| @IsOptional() | ||
| @IsString({ message: '目标分组ID必须是字符串' }) | ||
| targetGroupId?: string | ||
|
|
||
| @IsOptional() | ||
| @IsBoolean({ message: '是否自动创建分组必须是布尔值' }) | ||
| createMissingGroups?: boolean | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| import type { APIMethod } from 'prisma/generated/client' | ||
|
|
||
| /** 解析后的 API 信息预览 */ | ||
| export interface ParsedApiPreview { | ||
| /** 请求路径 */ | ||
| path: string | ||
| /** 请求方法 */ | ||
| method: APIMethod | ||
| /** API 名称 */ | ||
| name: string | ||
| /** 所属分组名称(基于 OpenAPI tags) */ | ||
| groupName: string | ||
| /** 描述 */ | ||
| description?: string | ||
| /** 是否与现有 API 冲突 */ | ||
| hasConflict: boolean | ||
| /** 冲突的现有 API ID */ | ||
| conflictApiId?: string | ||
| } | ||
|
|
||
| /** 解析后的分组信息预览 */ | ||
| export interface ParsedGroupPreview { | ||
| /** 分组名称 */ | ||
| name: string | ||
| /** 分组描述 */ | ||
| description?: string | ||
| /** 该分组下的 API 数量 */ | ||
| apiCount: number | ||
| } | ||
|
|
||
| /** 统计信息 */ | ||
| export interface ImportStats { | ||
| /** 总 API 数量 */ | ||
| totalApis: number | ||
| /** 新 API 数量 */ | ||
| newApis: number | ||
| /** 冲突 API 数量 */ | ||
| conflictApis: number | ||
| } | ||
|
|
||
| /** OpenAPI 文档基本信息 */ | ||
| export interface OpenApiInfo { | ||
| /** 文档标题 */ | ||
| title: string | ||
| /** 文档版本 */ | ||
| version: string | ||
| /** 文档描述 */ | ||
| description?: string | ||
| } | ||
|
|
||
| /** 解析预览响应 DTO */ | ||
| export class ImportPreviewResDto { | ||
| /** OpenAPI 文档基本信息 */ | ||
| info: OpenApiInfo | ||
| /** 分组列表 */ | ||
| groups: ParsedGroupPreview[] | ||
| /** API 列表 */ | ||
| apis: ParsedApiPreview[] | ||
| /** 统计信息 */ | ||
| stats: ImportStats | ||
| /** 原始 OpenAPI 文档内容(用于后续导入) */ | ||
| content: string | ||
| } | ||
|
|
||
| /** 导入结果中的单个 API 信息 */ | ||
| export interface ImportedApiResult { | ||
| /** API 名称 */ | ||
| name: string | ||
| /** 请求路径 */ | ||
| path: string | ||
| /** 请求方法 */ | ||
| method: APIMethod | ||
| /** 导入状态 */ | ||
| status: 'created' | 'updated' | 'skipped' | 'failed' | ||
| /** 失败原因 */ | ||
| error?: string | ||
| /** 创建的 API ID */ | ||
| apiId?: string | ||
| } | ||
|
|
||
| /** 导入执行结果响应 DTO */ | ||
| export class ImportResultResDto { | ||
| /** 是否成功 */ | ||
| success: boolean | ||
| /** 导入的 API 结果列表 */ | ||
| results: ImportedApiResult[] | ||
| /** 成功创建数量 */ | ||
| createdCount: number | ||
| /** 成功更新数量 */ | ||
| updatedCount: number | ||
| /** 跳过数量 */ | ||
| skippedCount: number | ||
| /** 失败数量 */ | ||
| failedCount: number | ||
| /** 创建的分组名称列表 */ | ||
| createdGroups: string[] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export * from './import-openapi.dto' | ||
| export * from './import-preview.dto' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import type { FastifyRequest } from 'fastify' | ||
| import { Body, Controller, Param, Post, Req, UseGuards } from '@nestjs/common' | ||
| import { ApiBody, ApiConsumes, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger' | ||
| import { ProjectPermissions, RequireProjectMember } from '@/common/decorators/permissions.decorator' | ||
| import { ReqUser } from '@/common/decorators/req-user.decorator' | ||
| import { ResMsg } from '@/common/decorators/res-msg.decorator' | ||
| import { AuthGuard } from '@/common/guards/auth.guard' | ||
| import { PermissionsGuard } from '@/common/guards/permissions.guard' | ||
| import { ExecuteImportReqDto, ParseOpenapiReqDto } from './dto' | ||
| import { ImportService } from './import.service' | ||
|
|
||
| @ApiTags('OpenAPI 导入') | ||
| @Controller('api/:projectId/import') | ||
| @UseGuards(AuthGuard, PermissionsGuard) | ||
| export class ImportController { | ||
| constructor(private readonly importService: ImportService) {} | ||
|
|
||
| @Post('openapi/parse') | ||
| @RequireProjectMember() | ||
| @ProjectPermissions(['api:create'], 'projectId') | ||
| @ResMsg('OpenAPI 文档解析成功') | ||
| @ApiOperation({ summary: '解析 OpenAPI 文档' }) | ||
| @ApiParam({ name: 'projectId', description: '项目ID' }) | ||
| @ApiConsumes('multipart/form-data', 'application/json') | ||
| @ApiBody({ | ||
| description: '上传 OpenAPI 文件或提供内容/URL', | ||
| schema: { | ||
| type: 'object', | ||
| properties: { | ||
| file: { type: 'string', format: 'binary', description: 'OpenAPI 文件 (JSON/YAML)' }, | ||
| content: { type: 'string', description: 'OpenAPI 文档内容' }, | ||
| url: { type: 'string', description: 'OpenAPI 文档 URL' }, | ||
| }, | ||
| }, | ||
| }) | ||
| async parseOpenapi( | ||
| @Param('projectId') projectId: string, | ||
| @Req() request: FastifyRequest, | ||
| @Body() dto: ParseOpenapiReqDto, | ||
| ) { | ||
| let fileContent: string | undefined | ||
|
|
||
| // 如果是上传文件,直接读取内容 | ||
| if (request.isMultipart()) { | ||
| const file = await request.file() | ||
| if (file) { | ||
| const buffer = await file.toBuffer() | ||
| fileContent = buffer.toString('utf-8') | ||
| } | ||
| } | ||
nonhana marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return this.importService.parseOpenapi(dto, projectId, fileContent) | ||
| } | ||
|
|
||
| @Post('openapi/execute') | ||
| @RequireProjectMember() | ||
| @ProjectPermissions(['api:create'], 'projectId') | ||
| @ResMsg('OpenAPI 文档导入成功') | ||
| @ApiOperation({ summary: '执行 OpenAPI 导入' }) | ||
| @ApiParam({ name: 'projectId', description: '项目ID' }) | ||
| async executeImport( | ||
| @Param('projectId') projectId: string, | ||
| @Body() dto: ExecuteImportReqDto, | ||
| @ReqUser('id') userId: string, | ||
| ) { | ||
| return this.importService.executeImport(dto, projectId, userId) | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.