-
-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathfix-openapi.mjs
More file actions
108 lines (95 loc) · 3.24 KB
/
fix-openapi.mjs
File metadata and controls
108 lines (95 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { readFileSync, writeFileSync } from "fs";
import { join } from "path";
const openapiPath = join(process.cwd(), "public", "openapi.json");
console.log("Fixing OpenAPI schema...");
try {
let openapi = JSON.parse(readFileSync(openapiPath, "utf8"));
let unwrapped = false;
// If the spec is nested (e.g. result.data.json from a migrated/source API), use the inner spec
if (openapi.result?.data?.json && typeof openapi.result.data.json === "object") {
openapi = openapi.result.data.json;
unwrapped = true;
console.log("✓ Unwrapped nested OpenAPI spec (result.data.json)");
}
let fixed = 0;
let securityFixed = false;
// Remove Authorization security scheme and add x-api-key
if (!openapi.components) {
openapi.components = {};
}
if (!openapi.components.securitySchemes) {
openapi.components.securitySchemes = {};
}
// Remove old Authorization scheme
if (openapi.components.securitySchemes["Authorization"]) {
delete openapi.components.securitySchemes["Authorization"];
securityFixed = true;
}
// Add x-api-key scheme
openapi.components.securitySchemes["x-api-key"] = {
type: "apiKey",
in: "header",
name: "x-api-key",
description: "API key authentication. Use YOUR-GENERATED-API-KEY",
"x-default": "your-key",
};
securityFixed = true;
// Replace global security from Authorization to x-api-key
if (openapi.security) {
openapi.security = openapi.security.filter((sec) => !sec["Authorization"]);
} else {
openapi.security = [];
}
const hasApiKeySecurity = openapi.security.some((sec) => sec["x-api-key"]);
if (!hasApiKeySecurity) {
openapi.security.push({ "x-api-key": [] });
securityFixed = true;
}
// Replace Authorization with x-api-key in all operation security
for (const [path, pathItem] of Object.entries(openapi.paths || {})) {
for (const [method, operation] of Object.entries(pathItem)) {
if (operation && operation.security) {
// Replace Authorization with x-api-key
operation.security = operation.security.map((sec) => {
if (sec["Authorization"] !== undefined) {
securityFixed = true;
return { "x-api-key": [] };
}
return sec;
});
}
}
}
// Fix empty response schemas
for (const [path, pathItem] of Object.entries(openapi.paths || {})) {
for (const [method, operation] of Object.entries(pathItem)) {
if (operation.responses) {
for (const [status, response] of Object.entries(operation.responses)) {
if (response.content && response.content["application/json"]) {
const content = response.content["application/json"];
// Check if schema is completely empty or missing
if (Object.keys(content).length === 0 || !content.schema) {
response.content["application/json"] = {
schema: {
type: "object",
description: "Successful response",
},
};
fixed++;
}
}
}
}
}
}
if (unwrapped || fixed > 0 || securityFixed) {
writeFileSync(openapiPath, JSON.stringify(openapi, null, 2));
if (fixed > 0) console.log(`✓ Fixed ${fixed} empty response schemas`);
if (securityFixed) console.log("✓ Added x-api-key security scheme");
} else {
console.log("✓ No fixes needed");
}
} catch (error) {
console.error("Error fixing OpenAPI schema:", error.message);
process.exit(1);
}