UNPKG

breathe-api

Version:

Model Context Protocol server for Breathe HR APIs with Swagger/OpenAPI support - also works with custom APIs

92 lines 3.49 kB
import SwaggerParser from '@apidevtools/swagger-parser'; import axios from 'axios'; import * as yaml from 'js-yaml'; import { generateTypesFromSchema } from '../utils/type-generator.js'; import { swaggerCache, getCachedOrFetch, generateCacheKey, requestQueue } from '../utils/cache.js'; export async function parseSwagger(input) { let spec; if (input.url) { const cacheKey = generateCacheKey({ url: input.url, headers: input.headers }); spec = await getCachedOrFetch(swaggerCache, cacheKey, async () => { return requestQueue.add(async () => { const config = {}; if (input.headers) { config.headers = input.headers; } try { const response = await axios.get(input.url, config); if (input.url.endsWith('.yaml') || input.url.endsWith('.yml') || (typeof response.data === 'string' && (response.data.includes('openapi:') || response.data.includes('swagger:')))) { return yaml.load(response.data); } else { return response.data; } } catch (error) { if (error.response?.status === 401) { throw new Error(`Authentication failed for ${input.url}. Please ensure proper credentials are provided.`); } throw error; } }); }); } else if (input.spec) { spec = input.spec; } else { throw new Error('Either url or spec must be provided'); } let dereferenced; try { const parsed = await SwaggerParser.validate(spec); dereferenced = await SwaggerParser.dereference(parsed); } catch (error) { console.warn('Warning: Could not fully validate/dereference spec:', error.message); console.warn('Proceeding with partial spec analysis...'); dereferenced = spec; } const paths = Object.keys(dereferenced.paths || {}); const operations = []; for (const path of paths) { const pathItem = dereferenced.paths[path]; for (const method of Object.keys(pathItem)) { if (['get', 'post', 'put', 'delete', 'patch'].includes(method.toLowerCase())) { const operation = pathItem[method]; operations.push({ path, method: method.toUpperCase(), operationId: operation.operationId, summary: operation.summary, }); } } } const schemas = Object.keys(dereferenced.components?.schemas || dereferenced.definitions || {}); let baseUrl = ''; if (dereferenced.servers && dereferenced.servers.length > 0) { baseUrl = dereferenced.servers[0].url; } else if (dereferenced.host) { const scheme = dereferenced.schemes?.[0] || 'https'; const basePath = dereferenced.basePath || ''; baseUrl = `${scheme}://${dereferenced.host}${basePath}`; } const result = { spec: dereferenced, paths, operations, schemas, baseUrl, }; if (input.generateTypes) { result.types = await generateTypesFromSchema(dereferenced); } return result; } //# sourceMappingURL=swagger-parser.js.map