arela
Version:
AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.
165 lines (160 loc) • 5.28 kB
JavaScript
/**
* Generate HTTP client from OpenAPI spec
*/
export function generateClient(spec, serviceName, baseURL) {
const className = `${serviceName}Client`;
let output = `/**
* Auto-generated API client from OpenAPI spec
* DO NOT EDIT - This file is generated by Arela
* @see https://axios-http.com
*/
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import * as types from './types';
import * as schemas from './schemas';
export interface ${className}Config {
baseURL: string;
token?: string;
timeout?: number;
}
export class ${className} {
private client: AxiosInstance;
constructor(config: ${className}Config) {
this.client = axios.create({
baseURL: config.baseURL,
timeout: config.timeout || 30000,
headers: {
'Content-Type': 'application/json',
...(config.token && { Authorization: \`Bearer \${config.token}\` }),
},
});
}
`;
// Generate methods for each endpoint
const methods = [];
for (const [path, pathItem] of Object.entries(spec.paths)) {
if (typeof pathItem !== 'object')
continue;
for (const [method, operation] of Object.entries(pathItem)) {
if (!operation || typeof operation !== 'object')
continue;
if (method === 'parameters')
continue; // Skip parameters key
const methodCode = generateMethod(path, method, operation);
if (methodCode)
methods.push(methodCode);
}
}
output += methods.join('\n\n');
output += '\n}\n';
return output;
}
function generateMethod(path, method, operation) {
const methodName = generateMethodName(path, method, operation);
const pathParams = extractPathParams(path);
const queryParams = (operation.parameters || []).filter((p) => p.in === 'query');
const hasBody = ['post', 'put', 'patch'].includes(method.toLowerCase());
// Build parameter list
const params = [];
// Add path parameters
for (const param of pathParams) {
params.push(`${param}: string | number`);
}
// Add body parameter
if (hasBody) {
params.push('data?: any');
}
// Add query parameters
if (queryParams.length > 0) {
params.push('params?: Record<string, any>');
}
// Add config parameter
params.push('config?: AxiosRequestConfig');
const parametersStr = params.join(', ');
const methodUpper = method.toUpperCase();
// Build URL
const urlTemplate = path.replace(/{([^}]+)}/g, '${$1}');
const urlExpr = `\`${urlTemplate}\``;
// Build axios call
let axiosCall = '';
const configParts = [];
if (queryParams.length > 0) {
configParts.push('params');
}
configParts.push('...config');
const configStr = configParts.length > 0 ? `, { ${configParts.join(', ')} }` : '';
if (hasBody) {
axiosCall = `this.client.${method.toLowerCase()}(${urlExpr}, data${configStr})`;
}
else {
axiosCall = `this.client.${method.toLowerCase()}(${urlExpr}${configStr})`;
}
// Build return type
const returnType = getReturnType(operation);
const methodCode = ` /**
* ${operation.summary || operation.description || `${methodUpper} ${path}`}
*/
async ${methodName}(${parametersStr}): Promise<${returnType}> {
const response = await ${axiosCall};
return response.data;
}`;
return methodCode;
}
function generateMethodName(path, method, operation) {
if (operation.operationId) {
return camelCase(operation.operationId);
}
const parts = path.split('/').filter((p) => p && !p.startsWith('{'));
const resource = parts[parts.length - 1] || 'resource';
const action = getActionFromMethod(method);
return `${action}${capitalize(singularize(resource))}`;
}
function getReturnType(operation) {
const responses = operation.responses || {};
// Try to find successful response
const successCodes = ['200', '201'];
for (const code of successCodes) {
if (responses[code]) {
return 'any'; // Simplified - could be enhanced with actual type extraction
}
}
return 'any';
}
function extractPathParams(path) {
const matches = path.match(/{([^}]+)}/g);
return matches ? matches.map((m) => m.slice(1, -1)) : [];
}
function getActionFromMethod(method) {
const m = method.toLowerCase();
switch (m) {
case 'get':
return 'get';
case 'post':
return 'create';
case 'put':
return 'update';
case 'patch':
return 'patch';
case 'delete':
return 'delete';
default:
return 'call';
}
}
function singularize(word) {
if (word.endsWith('ies'))
return word.slice(0, -3) + 'y';
if (word.endsWith('es'))
return word.slice(0, -2);
if (word.endsWith('s'))
return word.slice(0, -1);
return word;
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function camelCase(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase()))
.replace(/\s+/g, '');
}
//# sourceMappingURL=client-generator.js.map