first
This commit is contained in:
271
extract-complete-api-parameters.js
Normal file
271
extract-complete-api-parameters.js
Normal file
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* @fileoverview Extract complete API parameter specifications from api-docs.json
|
||||
* Parse every API endpoint with complete parameter specifications including names, types,
|
||||
* required/optional status, descriptions, and request body schemas.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
/**
|
||||
* Extract complete parameter specifications from API documentation
|
||||
*/
|
||||
function extractCompleteAPIParameters() {
|
||||
try {
|
||||
console.log("=== EXTRACTING COMPLETE API PARAMETER SPECIFICATIONS ===");
|
||||
console.log("");
|
||||
|
||||
// Read the API documentation
|
||||
const apiDocsPath = path.join(process.cwd(), "api-docs-analysis.json");
|
||||
const apiDocsContent = fs.readFileSync(apiDocsPath, "utf8");
|
||||
const apiDocs = JSON.parse(apiDocsContent);
|
||||
|
||||
const allEndpoints = [];
|
||||
const parameterStats = {
|
||||
totalEndpoints: 0,
|
||||
endpointsWithParameters: 0,
|
||||
totalParameters: 0,
|
||||
requiredParameters: 0,
|
||||
optionalParameters: 0,
|
||||
pathParameters: 0,
|
||||
queryParameters: 0,
|
||||
bodyParameters: 0,
|
||||
};
|
||||
|
||||
// Process each tag and its endpoints in the API documentation
|
||||
Object.keys(apiDocs.endpointsByTag || {}).forEach((tag) => {
|
||||
const endpoints = apiDocs.endpointsByTag[tag];
|
||||
|
||||
endpoints.forEach((endpoint) => {
|
||||
parameterStats.totalEndpoints++;
|
||||
|
||||
const endpointData = {
|
||||
path: endpoint.path,
|
||||
method: endpoint.method.toUpperCase(),
|
||||
operationId: endpoint.operationId || null,
|
||||
summary: endpoint.summary || "",
|
||||
description: endpoint.description || "",
|
||||
tags: endpoint.tags || [tag],
|
||||
security: endpoint.security || [],
|
||||
requiresAuth: endpoint.requiresAuth || false,
|
||||
parameters: {
|
||||
path: [],
|
||||
query: [],
|
||||
body: [],
|
||||
header: [],
|
||||
},
|
||||
requestBody: endpoint.requestBody || null,
|
||||
responses: endpoint.responses || {},
|
||||
};
|
||||
|
||||
let hasParameters = false;
|
||||
|
||||
// Extract path and query parameters
|
||||
if (endpoint.parameters && Array.isArray(endpoint.parameters)) {
|
||||
endpoint.parameters.forEach((param) => {
|
||||
hasParameters = true;
|
||||
parameterStats.totalParameters++;
|
||||
|
||||
const paramData = {
|
||||
name: param.name,
|
||||
type: param.schema?.type || param.type || "string",
|
||||
format: param.schema?.format || param.format || null,
|
||||
required: param.required === true,
|
||||
description: param.description || "",
|
||||
in: param.in,
|
||||
enum: param.schema?.enum || param.enum || null,
|
||||
example: param.schema?.example || param.example || null,
|
||||
};
|
||||
|
||||
if (param.required) {
|
||||
parameterStats.requiredParameters++;
|
||||
} else {
|
||||
parameterStats.optionalParameters++;
|
||||
}
|
||||
|
||||
switch (param.in) {
|
||||
case "path":
|
||||
endpointData.parameters.path.push(paramData);
|
||||
parameterStats.pathParameters++;
|
||||
break;
|
||||
case "query":
|
||||
endpointData.parameters.query.push(paramData);
|
||||
parameterStats.queryParameters++;
|
||||
break;
|
||||
case "header":
|
||||
endpointData.parameters.header.push(paramData);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Extract request body parameters
|
||||
if (endpoint.requestBody) {
|
||||
hasParameters = true;
|
||||
endpointData.requestBody = {
|
||||
required: endpoint.requestBody.required === true,
|
||||
description: endpoint.requestBody.description || "",
|
||||
content: {},
|
||||
};
|
||||
|
||||
// Process different content types
|
||||
Object.keys(endpoint.requestBody.content || {}).forEach(
|
||||
(contentType) => {
|
||||
const content = endpoint.requestBody.content[contentType];
|
||||
endpointData.requestBody.content[contentType] = {
|
||||
schema: content.schema || {},
|
||||
examples: content.examples || {},
|
||||
};
|
||||
|
||||
// Extract properties from schema
|
||||
if (content.schema && content.schema.properties) {
|
||||
Object.keys(content.schema.properties).forEach((propName) => {
|
||||
const prop = content.schema.properties[propName];
|
||||
parameterStats.totalParameters++;
|
||||
parameterStats.bodyParameters++;
|
||||
|
||||
const isRequired = (content.schema.required || []).includes(
|
||||
propName
|
||||
);
|
||||
if (isRequired) {
|
||||
parameterStats.requiredParameters++;
|
||||
} else {
|
||||
parameterStats.optionalParameters++;
|
||||
}
|
||||
|
||||
const bodyParam = {
|
||||
name: propName,
|
||||
type: prop.type || "string",
|
||||
format: prop.format || null,
|
||||
required: isRequired,
|
||||
description: prop.description || "",
|
||||
enum: prop.enum || null,
|
||||
example: prop.example || null,
|
||||
items: prop.items || null,
|
||||
properties: prop.properties || null,
|
||||
};
|
||||
|
||||
endpointData.parameters.body.push(bodyParam);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (hasParameters) {
|
||||
parameterStats.endpointsWithParameters++;
|
||||
}
|
||||
|
||||
allEndpoints.push(endpointData);
|
||||
});
|
||||
});
|
||||
|
||||
// Sort endpoints by path and method
|
||||
allEndpoints.sort((a, b) => {
|
||||
if (a.path !== b.path) return a.path.localeCompare(b.path);
|
||||
return a.method.localeCompare(b.method);
|
||||
});
|
||||
|
||||
// Save complete endpoint data
|
||||
const outputPath = path.join(process.cwd(), "complete-api-parameters.json");
|
||||
fs.writeFileSync(outputPath, JSON.stringify(allEndpoints, null, 2));
|
||||
|
||||
// Generate parameter statistics report
|
||||
console.log("📊 PARAMETER EXTRACTION STATISTICS:");
|
||||
console.log(`Total endpoints: ${parameterStats.totalEndpoints}`);
|
||||
console.log(
|
||||
`Endpoints with parameters: ${parameterStats.endpointsWithParameters}`
|
||||
);
|
||||
console.log(`Total parameters: ${parameterStats.totalParameters}`);
|
||||
console.log(`Required parameters: ${parameterStats.requiredParameters}`);
|
||||
console.log(`Optional parameters: ${parameterStats.optionalParameters}`);
|
||||
console.log(`Path parameters: ${parameterStats.pathParameters}`);
|
||||
console.log(`Query parameters: ${parameterStats.queryParameters}`);
|
||||
console.log(`Body parameters: ${parameterStats.bodyParameters}`);
|
||||
console.log("");
|
||||
|
||||
// Generate authentication type breakdown
|
||||
const authTypeBreakdown = {};
|
||||
allEndpoints.forEach((endpoint) => {
|
||||
let authType = "public";
|
||||
|
||||
if (endpoint.security && endpoint.security.length > 0) {
|
||||
// Determine auth type based on security requirements
|
||||
const securitySchemes = endpoint.security[0];
|
||||
if (securitySchemes.sanctum) {
|
||||
// Determine specific auth type based on path patterns
|
||||
if (
|
||||
endpoint.path.includes("/api/emr/") ||
|
||||
endpoint.path.includes("/emr-api/") ||
|
||||
endpoint.path.includes("/api/provider/") ||
|
||||
endpoint.path.includes("/api/practitioners") ||
|
||||
endpoint.path.includes("/api/appointment") ||
|
||||
endpoint.path.includes("/api/patient") ||
|
||||
endpoint.path.includes("/api/forms") ||
|
||||
endpoint.path.includes("/api/medical-problems") ||
|
||||
endpoint.path.includes("/api/locations") ||
|
||||
endpoint.path.includes("/api/tasks") ||
|
||||
endpoint.path.includes("/api/user") ||
|
||||
endpoint.path.includes("/api/add-") ||
|
||||
endpoint.path.includes("/api/get-") ||
|
||||
endpoint.path.includes("/api/update-") ||
|
||||
endpoint.path.includes("/api/store-") ||
|
||||
endpoint.path.includes("/api/save-") ||
|
||||
endpoint.path.includes("/api/delete-") ||
|
||||
endpoint.path.includes("/api/assistant/") ||
|
||||
endpoint.path.includes("/api/token/") ||
|
||||
endpoint.path.includes("/inventory") ||
|
||||
endpoint.path.includes("/tags/") ||
|
||||
endpoint.path.includes("/phone-log")
|
||||
) {
|
||||
authType = "provider";
|
||||
} else if (
|
||||
endpoint.path.includes("/api/frontend/patient") ||
|
||||
endpoint.path.includes("/patient/")
|
||||
) {
|
||||
authType = "patient";
|
||||
} else if (endpoint.path.includes("/partner/")) {
|
||||
authType = "partner";
|
||||
} else if (endpoint.path.includes("/affiliate/")) {
|
||||
authType = "affiliate";
|
||||
} else if (endpoint.path.includes("/network/")) {
|
||||
authType = "network";
|
||||
} else {
|
||||
authType = "provider"; // Default for authenticated endpoints
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
authTypeBreakdown[authType] = (authTypeBreakdown[authType] || 0) + 1;
|
||||
});
|
||||
|
||||
console.log("🔐 AUTHENTICATION TYPE BREAKDOWN:");
|
||||
Object.keys(authTypeBreakdown)
|
||||
.sort()
|
||||
.forEach((authType) => {
|
||||
console.log(`${authType}: ${authTypeBreakdown[authType]} endpoints`);
|
||||
});
|
||||
console.log("");
|
||||
|
||||
console.log(
|
||||
`✅ Complete API parameter specifications extracted to: ${outputPath}`
|
||||
);
|
||||
console.log(`📋 Total endpoints processed: ${allEndpoints.length}`);
|
||||
|
||||
return {
|
||||
endpoints: allEndpoints,
|
||||
statistics: parameterStats,
|
||||
authTypeBreakdown,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error extracting API parameters:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the extraction
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
extractCompleteAPIParameters();
|
||||
}
|
||||
|
||||
export { extractCompleteAPIParameters };
|
Reference in New Issue
Block a user