Skip to main content
Glama
backend-api-service-implementation-plan.md21.1 kB
# MCP Swagger 后端 API 服务实施方案 ## 📋 方案概述 将 OpenAPI/Swagger 解析功能从前端提取为独立的后端 API 服务,实现前后端彻底分离,提升系统架构的可维护性、可扩展性和性能。 ## 🎯 核心优势 ### 1. 架构优势 - **关注点分离**: 前端专注UI交互,后端专注业务逻辑 - **技术栈解耦**: 前端无需处理复杂的Node.js依赖 - **独立部署**: 前后端可以独立构建、部署和扩展 - **版本管理**: API版本化管理,支持向后兼容 ### 2. 性能优势 - **服务端解析**: 避免大型解析库在浏览器中加载 - **缓存机制**: 服务端可实现智能缓存策略 - **并发处理**: 服务端可处理多个并发解析请求 - **资源优化**: 减少前端包体积 ### 3. 开发优势 - **调试便利**: 后端逻辑更容易调试和监控 - **测试友好**: API接口更容易进行单元测试和集成测试 - **扩展性强**: 可轻松添加新的解析格式和功能 ## 🏗️ 技术架构设计 ### 整体架构图 ``` ┌─────────────────────────────────────────────────────────────┐ │ 前端层 (Vue 3 + Vite) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ UI组件 │ │ 状态管理 │ │ HTTP客户端│ │ │ │ Naive UI │ │ Pinia │ │ Axios │ │ │ │ 表单/展示 │ │ 响应式 │ │ 拦截器 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────┼─────────────────────────────────┘ │ HTTP REST API ▼ ┌─────────────────────────────────────────────────────────────┐ │ API网关层 (Express.js) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 路由管理 │ │ 中间件 │ │ 错误处理 │ │ │ │ RESTful API │ │ CORS │ │ 统一响应 │ │ │ │ 参数验证 │ │ Body Parser│ │ 日志记录 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────┼─────────────────────────────────┘ │ 业务逻辑调用 ▼ ┌─────────────────────────────────────────────────────────────┐ │ 业务服务层 (Service Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 解析服务 │ │ 转换服务 │ │ 验证服务 │ │ │ │ ParserService│ │ConvertService│ │ValidateService│ │ │ │ 多格式支持 │ │ MCP转换 │ │ 规范检查 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────┼─────────────────────────────────┘ │ 核心库调用 ▼ ┌─────────────────────────────────────────────────────────────┐ │ 核心库层 (mcp-swagger-parser) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 解析器 │ │ 验证器 │ │ 转换器 │ │ │ │ 多格式解析 │ │ Schema校验 │ │ 格式转换 │ │ │ │ 错误处理 │ │ 结构验证 │ │ 数据映射 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## 🛠️ 实施计划 ### 阶段一: 后端API服务搭建 (1-2天) #### 1.1 创建独立的API服务模块 在现有的 monorepo 结构中新增: ``` packages/ ├── mcp-swagger-api/ # 🆕 新增API服务 │ ├── src/ │ │ ├── app.ts # Express应用入口 │ │ ├── server.ts # 服务器启动文件 │ │ ├── routes/ # 路由定义 │ │ │ ├── index.ts │ │ │ ├── parse.ts # 解析相关路由 │ │ │ ├── convert.ts # 转换相关路由 │ │ │ └── validate.ts # 验证相关路由 │ │ ├── services/ # 业务服务层 │ │ │ ├── parser.service.ts │ │ │ ├── converter.service.ts │ │ │ └── validator.service.ts │ │ ├── middlewares/ # 中间件 │ │ │ ├── error-handler.ts │ │ │ ├── cors.ts │ │ │ └── validation.ts │ │ ├── types/ # 类型定义 │ │ │ ├── api.ts │ │ │ └── request.ts │ │ └── utils/ # 工具函数 │ │ ├── response.ts │ │ └── logger.ts │ ├── package.json │ ├── tsconfig.json │ └── README.md ``` #### 1.2 API接口设计 ##### 核心API端点设计 ```typescript // 1. 解析接口 POST /api/v1/parse { "source": { "type": "url" | "file" | "text", "content": string, "encoding": "utf-8" | "base64" }, "options": { "strictMode": boolean, "resolveReferences": boolean, "validateSchema": boolean } } // 2. 验证接口 POST /api/v1/validate { "source": { "type": "url" | "file" | "text", "content": string }, "validationLevel": "basic" | "strict" | "extended" } // 3. 转换接口 POST /api/v1/convert { "source": { "type": "url" | "file" | "text", "content": string }, "config": { "outputFormat": "json" | "yaml", "includeExamples": boolean, "groupByTags": boolean, "customSettings": object } } // 4. 健康检查 GET /api/v1/health // 5. 服务信息 GET /api/v1/info ``` ##### 统一响应格式 ```typescript interface ApiResponse<T = any> { success: boolean; data?: T; error?: { code: string; message: string; details?: any; }; meta?: { timestamp: string; requestId: string; duration: number; }; } ``` ### 阶段二: 服务实现 (2-3天) #### 2.1 Express应用基础架构 ```typescript // src/app.ts import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import compression from 'compression'; import { errorHandler } from './middlewares/error-handler'; import { requestLogger } from './middlewares/logger'; import routes from './routes'; export function createApp() { const app = express(); // 安全中间件 app.use(helmet()); app.use(cors({ origin: process.env.FRONTEND_URL || 'http://localhost:5173', credentials: true })); // 基础中间件 app.use(compression()); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true })); // 日志中间件 app.use(requestLogger); // API路由 app.use('/api/v1', routes); // 错误处理 app.use(errorHandler); return app; } ``` #### 2.2 核心服务实现 ```typescript // src/services/parser.service.ts import { parseFromUrl, parseFromFile, parseFromString } from 'mcp-swagger-parser'; import type { InputSource, ParseOptions, ParseResult } from '../types/api'; export class ParserService { async parse(source: InputSource, options: ParseOptions): Promise<ParseResult> { try { let result; switch (source.type) { case 'url': result = await parseFromUrl(source.content, options); break; case 'file': result = await this.parseFromBase64File(source.content, options); break; case 'text': result = await parseFromString(source.content, options); break; default: throw new Error(`Unsupported source type: ${source.type}`); } return { success: true, spec: result.spec, apiInfo: this.extractApiInfo(result.spec), endpoints: this.extractEndpoints(result.spec), statistics: this.generateStatistics(result.spec) }; } catch (error) { throw new ParserError(`Parse failed: ${error.message}`, 'PARSE_ERROR'); } } private async parseFromBase64File(base64Content: string, options: ParseOptions) { const buffer = Buffer.from(base64Content, 'base64'); const content = buffer.toString('utf-8'); return await parseFromString(content, options); } private extractApiInfo(spec: any) { return { title: spec.info?.title || 'Untitled API', version: spec.info?.version || '1.0.0', description: spec.info?.description, serverUrl: spec.servers?.[0]?.url, totalEndpoints: Object.keys(spec.paths || {}).length }; } private extractEndpoints(spec: any) { // 端点提取逻辑 } private generateStatistics(spec: any) { // 统计信息生成逻辑 } } ``` #### 2.3 路由控制器实现 ```typescript // src/routes/parse.ts import { Router } from 'express'; import { ParserService } from '../services/parser.service'; import { validateRequest } from '../middlewares/validation'; import { asyncHandler } from '../utils/async-handler'; const router = Router(); const parserService = new ParserService(); router.post('/parse', validateRequest('parseRequest'), asyncHandler(async (req, res) => { const { source, options = {} } = req.body; const result = await parserService.parse(source, options); res.json({ success: true, data: result, meta: { timestamp: new Date().toISOString(), requestId: req.id, duration: Date.now() - req.startTime } }); }) ); export default router; ``` ### 阶段三: 前端适配 (1-2天) #### 3.1 API客户端封装 ```typescript // src/api/client.ts import axios, { AxiosInstance, AxiosResponse } from 'axios'; import type { ApiResponse, ParseRequest, ParseResult } from '@/types/api'; class ApiClient { private client: AxiosInstance; constructor() { this.client = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3001/api/v1', timeout: 30000, headers: { 'Content-Type': 'application/json', }, }); this.setupInterceptors(); } private setupInterceptors() { // 请求拦截器 this.client.interceptors.request.use( (config) => { console.log(`🚀 API Request: ${config.method?.toUpperCase()} ${config.url}`); return config; }, (error) => Promise.reject(error) ); // 响应拦截器 this.client.interceptors.response.use( (response: AxiosResponse<ApiResponse>) => { if (!response.data.success) { throw new Error(response.data.error?.message || 'API request failed'); } return response; }, (error) => { console.error('❌ API Error:', error.response?.data || error.message); return Promise.reject(error); } ); } async parse(request: ParseRequest): Promise<ParseResult> { const response = await this.client.post<ApiResponse<ParseResult>>('/parse', request); return response.data.data!; } async validate(request: ValidateRequest): Promise<ValidationResult> { const response = await this.client.post<ApiResponse<ValidationResult>>('/validate', request); return response.data.data!; } async convert(request: ConvertRequest): Promise<ConvertResult> { const response = await this.client.post<ApiResponse<ConvertResult>>('/convert', request); return response.data.data!; } async healthCheck(): Promise<{ status: 'ok' | 'error', timestamp: string }> { const response = await this.client.get<ApiResponse>('/health'); return response.data.data!; } } export const apiClient = new ApiClient(); ``` #### 3.2 前端服务层改造 ```typescript // src/services/parser.service.ts (前端) import { apiClient } from '@/api/client'; import type { InputSource, ConvertConfig, OpenApiInfo, ApiEndpoint, ConvertResult } from '@/types'; export class ParserService { /** * 验证 OpenAPI 规范 */ async validateOpenAPISpec(source: InputSource): Promise<ValidationResult> { try { return await apiClient.validate({ source, validationLevel: 'strict' }); } catch (error) { console.error('验证失败:', error); throw new ParserError(`验证失败: ${error.message}`, 'VALIDATION_ERROR'); } } /** * 解析 OpenAPI 规范获取基本信息 */ async parseApiInfo(source: InputSource): Promise<OpenApiInfo> { try { const result = await apiClient.parse({ source, options: { strictMode: false, resolveReferences: true, validateSchema: true } }); return result.apiInfo; } catch (error) { console.error('解析失败:', error); throw new ParserError(`解析失败: ${error.message}`, 'PARSE_ERROR'); } } /** * 解析端点信息 */ async parseEndpoints(source: InputSource): Promise<ApiEndpoint[]> { try { const result = await apiClient.parse({ source, options: { strictMode: false, resolveReferences: true, validateSchema: true } }); return result.endpoints; } catch (error) { console.error('端点解析失败:', error); throw new ParserError(`端点解析失败: ${error.message}`, 'ENDPOINT_PARSE_ERROR'); } } /** * 转换为 MCP 格式 */ async convertToMcp(source: InputSource, config: ConvertConfig): Promise<ConvertResult> { try { return await apiClient.convert({ source, config }); } catch (error) { console.error('转换失败:', error); throw new ParserError(`转换失败: ${error.message}`, 'CONVERT_ERROR'); } } } export const parserService = new ParserService(); ``` ### 阶段四: 部署配置 (1天) #### 4.1 开发环境配置 ```typescript // packages/mcp-swagger-api/src/config/development.ts export default { port: 3001, cors: { origin: ['http://localhost:5173', 'http://localhost:3000'], credentials: true }, logging: { level: 'debug', format: 'dev' }, cache: { enabled: false } }; ``` #### 4.2 生产环境配置 ```typescript // packages/mcp-swagger-api/src/config/production.ts export default { port: process.env.PORT || 3001, cors: { origin: process.env.FRONTEND_URL?.split(',') || ['https://yourdomain.com'], credentials: true }, logging: { level: 'info', format: 'combined' }, cache: { enabled: true, ttl: 300 // 5分钟 } }; ``` #### 4.3 Docker配置 ```dockerfile # packages/mcp-swagger-api/Dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY dist ./dist EXPOSE 3001 CMD ["node", "dist/server.js"] ``` ### 阶段五: 测试与优化 (1-2天) #### 5.1 API测试 ```typescript // packages/mcp-swagger-api/tests/api.test.ts import request from 'supertest'; import { createApp } from '../src/app'; describe('Parser API', () => { const app = createApp(); describe('POST /api/v1/parse', () => { it('should parse OpenAPI spec from URL', async () => { const response = await request(app) .post('/api/v1/parse') .send({ source: { type: 'url', content: 'https://petstore.swagger.io/v2/swagger.json' }, options: { strictMode: false, resolveReferences: true } }) .expect(200); expect(response.body.success).toBe(true); expect(response.body.data.apiInfo).toBeDefined(); expect(response.body.data.endpoints).toBeInstanceOf(Array); }); }); }); ``` #### 5.2 性能优化 ```typescript // src/middlewares/cache.ts import NodeCache from 'node-cache'; const cache = new NodeCache({ stdTTL: 300, // 5分钟默认缓存 checkperiod: 60 // 每分钟清理过期缓存 }); export function cacheMiddleware(ttl?: number) { return (req: Request, res: Response, next: NextFunction) => { const key = `${req.method}:${req.url}:${JSON.stringify(req.body)}`; const cached = cache.get(key); if (cached) { console.log(`🎯 Cache hit: ${key}`); return res.json(cached); } const originalSend = res.json; res.json = function(data) { if (res.statusCode === 200) { cache.set(key, data, ttl); console.log(`💾 Cache set: ${key}`); } return originalSend.call(this, data); }; next(); }; } ``` ## 🔧 脚本与工具 ### package.json 脚本配置 ```json { "scripts": { "dev:api": "pnpm --filter=mcp-swagger-api run dev", "dev:ui": "pnpm --filter=mcp-swagger-ui run dev", "dev:full": "concurrently \"pnpm run dev:api\" \"pnpm run dev:ui\"", "build:api": "pnpm --filter=mcp-swagger-api run build", "build:ui": "pnpm --filter=mcp-swagger-ui run build", "test:api": "pnpm --filter=mcp-swagger-api run test", "test:ui": "pnpm --filter=mcp-swagger-ui run test" } } ``` ### 开发启动脚本 ```bash #!/bin/bash # scripts/dev-full.sh echo "🚀 启动全栈开发环境..." # 启动API服务 echo "📡 启动API服务..." pnpm --filter=mcp-swagger-api run dev & API_PID=$! # 等待API服务启动 sleep 3 # 启动前端服务 echo "🎨 启动前端服务..." pnpm --filter=mcp-swagger-ui run dev & UI_PID=$! # 等待用户输入退出 echo "✅ 开发环境已启动" echo " - API服务: http://localhost:3001" echo " - 前端服务: http://localhost:5173" echo "" echo "按 Ctrl+C 退出..." # 捕获退出信号,清理进程 trap "kill $API_PID $UI_PID; exit" INT TERM wait ``` ## 📊 迁移对比 ### 改造前 (当前架构) ``` 前端 (Vue 3) ├── 直接引用 mcp-swagger-parser ├── 浏览器中执行解析逻辑 ❌ ├── 大量Node.js依赖打包 ❌ └── 解析错误调试困难 ❌ ``` ### 改造后 (目标架构) ``` 前端 (Vue 3) ├── HTTP API调用 ├── 轻量级客户端 ✅ └── 清晰的错误处理 ✅ 后端 API服务 (Express) ├── 专业的解析服务 ✅ ├── 缓存和性能优化 ✅ ├── 完整的错误处理 ✅ └── 独立测试和部署 ✅ ``` ## 🎯 实施建议 1. **渐进式迁移**: 可以先保留现有的mock模式,新增API模式作为选项 2. **向后兼容**: 保持现有的接口不变,内部实现切换到API调用 3. **错误处理**: 当API服务不可用时,自动降级到mock模式 4. **监控告警**: 添加API服务的健康检查和监控 ## 📈 预期收益 1. **开发效率**: 前后端独立开发,提升并行开发效率 2. **维护成本**: 清晰的架构边界,降低长期维护成本 3. **扩展能力**: 后端服务可独立扩展,支持更多客户端 4. **用户体验**: 更快的加载速度和更稳定的解析性能 这个方案充分利用了现有的 monorepo 架构和 mcp-swagger-parser 核心库,是一个既务实又具有前瞻性的技术方案。

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zaizaizhao/mcp-swagger-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server