UNPKG

@allma/core-cdk

Version:

Core AWS CDK constructs for deploying the Allma serverless AI orchestration platform.

92 lines 4.74 kB
import axios from 'axios'; import { JSONPath } from 'jsonpath-plus'; import { TransientStepError } from '@allma/core-types'; import { log_error, log_info } from '@allma/core-sdk'; import { TemplateService } from '../template-service'; /** * Executes a configured API call using the provided runtime state for data mapping and templating. * This is a centralized utility to be used by both the API_CALL step handler and the API_POLLING lambda. * * @param apiCallDefinition The configuration for the API call. * @param runtimeState The current flow runtime state. * @param correlationId A unique ID for logging and tracing. * @param templateSourceData Optional override for the data context used in template rendering. Defaults to `runtimeState.currentContextData`. * @returns A promise that resolves to the AxiosResponse. * @throws {TransientStepError} for 5xx server errors. * @throws {Error} for other axios or configuration errors. */ export const executeConfiguredApiCall = async (apiCallDefinition, runtimeState, correlationId, templateSourceData) => { const templateService = TemplateService.getInstance(); const sourceData = templateSourceData || runtimeState.currentContextData; // 1. Render the API URL const { context: urlContext } = await templateService.buildContextFromMappings(apiCallDefinition.apiUrlTemplate.contextMappings, sourceData, correlationId); // Render URL with the built context const apiUrl = templateService.render(apiCallDefinition.apiUrlTemplate.template, urlContext); log_info(`Preparing API call to ${apiUrl}`, { method: apiCallDefinition.apiHttpMethod }, correlationId); // 2. Build dynamic headers const dynamicHeaders = {}; if (apiCallDefinition.apiHeadersTemplate) { for (const [header, jsonPath] of Object.entries(apiCallDefinition.apiHeadersTemplate)) { const value = JSONPath({ path: jsonPath, json: sourceData, wrap: false }); if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { dynamicHeaders[header] = String(value); } } } // Combine static and dynamic headers, with dynamic headers taking precedence const finalHeaders = { ...apiCallDefinition.apiStaticHeaders, ...dynamicHeaders }; // 3. Construct request body using the complex mapping logic let requestBody; if (apiCallDefinition.requestBodyTemplate && Object.keys(apiCallDefinition.requestBodyTemplate).length > 0) { const { context } = await templateService.buildContextFromMappings(apiCallDefinition.requestBodyTemplate, sourceData, correlationId); requestBody = context; } else if (apiCallDefinition.customConfig?.requestBodyPath) { requestBody = JSONPath({ path: apiCallDefinition.customConfig.requestBodyPath, json: sourceData, wrap: false }); } // 4. Configure and execute the request const config = { method: apiCallDefinition.apiHttpMethod, url: apiUrl, headers: finalHeaders, data: requestBody, // Axios handles undefined data correctly timeout: apiCallDefinition.customConfig?.timeoutMs || 10000, }; try { const response = await axios(config); log_info(`API call to ${apiUrl} succeeded with status ${response.status}`, {}, correlationId); return response; } catch (error) { if (axios.isAxiosError(error)) { log_error(`API call failed`, { url: apiUrl, status: error.response?.status, data: error.response?.data, message: error.message, }, correlationId); // Make transient server errors retryable by the orchestrator if (error.response && error.response.status >= 500) { throw new TransientStepError(`API call failed with server error: ${error.response.status}`); } } else { log_error(`API call failed with a non-network error.`, { error: error.message }, correlationId); } // Re-throw for the caller to handle throw error; } }; /** * An utility for making a direct POST request with a JSON payload. * Used for internal system-level calls like flow resumption where a full ApiCallDefinition is overkill. * @param url The URL to post to. * @param payload The data to send. * @param timeout Milliseconds before the request times out. * @returns A promise that resolves to the AxiosResponse. */ export const postSimpleJson = async (url, payload, timeout = 5000) => { // This function centralizes the direct axios.post call. return axios.post(url, payload, { timeout }); }; //# sourceMappingURL=api-executor.js.map