9370d2c898
Validate Flux manifests / kustomize-build (pull_request) Failing after 8s
Closes leeworks-agents/api-company#100 - scripts/publish-openapi.js: Node.js script using only built-in modules (https, fs, path — no extra deps) that uploads each API's openapi.yaml to the RapidAPI Platform API via PUT multipart/form-data. - Reads RAPIDAPI_KEY/RAPIDAPI_PLATFORM_KEY from environment. - Skips silently per API if API ID / version ID not set. - Skips all uploads if RAPIDAPI_KEY not set (exits 0). - Exits non-zero on any HTTP error. - Logs: '✓ Published {api-name} spec to RapidAPI' on success. - Passes 'node --check' syntax validation. - .gitea/workflows/publish-openapi.yaml: triggers on push to main when apis/*/openapi.yaml changes. - Runs Redocly CLI lint (fails pipeline on spec errors). - Detects changed specs via git diff. - Calls publish-openapi.js; no secrets = skip, not crash.
135 lines
4.0 KiB
JavaScript
135 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* publish-openapi.js
|
|
*
|
|
* Uploads each API's openapi.yaml to the RapidAPI Platform API.
|
|
* Environment variables required per API (skips silently if not set):
|
|
* RAPIDAPI_KEY — RapidAPI Platform API bearer token
|
|
* RAPIDAPI_ZIP_API_ID — API ID for ZIP Enrichment on RapidAPI
|
|
* RAPIDAPI_ZIP_VERSION_ID — Version ID for ZIP Enrichment
|
|
* RAPIDAPI_HOLIDAYS_API_ID
|
|
* RAPIDAPI_HOLIDAYS_VERSION_ID
|
|
* RAPIDAPI_AQI_API_ID
|
|
* RAPIDAPI_AQI_VERSION_ID
|
|
*
|
|
* Usage: node scripts/publish-openapi.js
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const https = require('https');
|
|
|
|
const RAPIDAPI_KEY = process.env.RAPIDAPI_KEY || process.env.RAPIDAPI_PLATFORM_KEY;
|
|
|
|
if (!RAPIDAPI_KEY) {
|
|
console.log('⚠️ RAPIDAPI_KEY / RAPIDAPI_PLATFORM_KEY not set — skipping all spec uploads.');
|
|
process.exit(0);
|
|
}
|
|
|
|
const APIS = [
|
|
{
|
|
name: 'zip-enrichment',
|
|
specPath: path.join(__dirname, '..', 'apis', 'zip-enrichment', 'openapi.yaml'),
|
|
apiId: process.env.RAPIDAPI_ZIP_API_ID,
|
|
versionId: process.env.RAPIDAPI_ZIP_VERSION_ID,
|
|
},
|
|
{
|
|
name: 'holidays',
|
|
specPath: path.join(__dirname, '..', 'apis', 'holidays', 'openapi.yaml'),
|
|
apiId: process.env.RAPIDAPI_HOLIDAYS_API_ID,
|
|
versionId: process.env.RAPIDAPI_HOLIDAYS_VERSION_ID,
|
|
},
|
|
{
|
|
name: 'air-quality',
|
|
specPath: path.join(__dirname, '..', 'apis', 'air-quality', 'openapi.yaml'),
|
|
apiId: process.env.RAPIDAPI_AQI_API_ID,
|
|
versionId: process.env.RAPIDAPI_AQI_VERSION_ID,
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Build a multipart/form-data body from a file buffer.
|
|
* Returns { body: Buffer, boundary: string }
|
|
*/
|
|
function buildMultipart(fieldName, filename, fileBuffer, contentType = 'application/yaml') {
|
|
const boundary = '----FormBoundary' + Math.random().toString(36).slice(2);
|
|
const CRLF = '\r\n';
|
|
const parts = [
|
|
Buffer.from(
|
|
`--${boundary}${CRLF}` +
|
|
`Content-Disposition: form-data; name="${fieldName}"; filename="${filename}"${CRLF}` +
|
|
`Content-Type: ${contentType}${CRLF}${CRLF}`
|
|
),
|
|
fileBuffer,
|
|
Buffer.from(`${CRLF}--${boundary}--${CRLF}`),
|
|
];
|
|
return { body: Buffer.concat(parts), boundary };
|
|
}
|
|
|
|
/**
|
|
* Upload a spec file to RapidAPI Platform API.
|
|
* Returns a promise that resolves with the response status code.
|
|
*/
|
|
function uploadSpec(api) {
|
|
return new Promise((resolve, reject) => {
|
|
if (!api.apiId || !api.versionId) {
|
|
console.log(`⏭️ Skipping ${api.name}: API ID or Version ID not configured.`);
|
|
return resolve(null);
|
|
}
|
|
|
|
if (!fs.existsSync(api.specPath)) {
|
|
console.log(`⏭️ Skipping ${api.name}: spec file not found at ${api.specPath}`);
|
|
return resolve(null);
|
|
}
|
|
|
|
const fileBuffer = fs.readFileSync(api.specPath);
|
|
const { body, boundary } = buildMultipart('spec', 'openapi.yaml', fileBuffer);
|
|
|
|
const options = {
|
|
hostname: 'platformapi1.p.rapidapi.com',
|
|
path: `/v1/apis/${api.apiId}/versions/${api.versionId}`,
|
|
method: 'PUT',
|
|
headers: {
|
|
'Authorization': `Bearer ${RAPIDAPI_KEY}`,
|
|
'X-RapidAPI-Key': RAPIDAPI_KEY,
|
|
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
'Content-Length': body.length,
|
|
},
|
|
};
|
|
|
|
const req = https.request(options, (res) => {
|
|
let data = '';
|
|
res.on('data', (chunk) => { data += chunk; });
|
|
res.on('end', () => {
|
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
console.log(`✓ Published ${api.name} spec to RapidAPI (HTTP ${res.statusCode})`);
|
|
resolve(res.statusCode);
|
|
} else {
|
|
reject(new Error(`Failed to publish ${api.name}: HTTP ${res.statusCode} — ${data}`));
|
|
}
|
|
});
|
|
});
|
|
|
|
req.on('error', reject);
|
|
req.write(body);
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
let hasError = false;
|
|
for (const api of APIS) {
|
|
try {
|
|
await uploadSpec(api);
|
|
} catch (err) {
|
|
console.error(`✗ ${err.message}`);
|
|
hasError = true;
|
|
}
|
|
}
|
|
if (hasError) {
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|