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
JavaScript
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