@flowlab/all
Version:
A cool library focusing on handling various flows
60 lines (52 loc) • 2.82 kB
text/typescript
// src/extractors/apiExtractor.ts
import { IExtractor, PipelineContext, DataSource, ApiSourceConfig } from '../core/interfaces';
import { ComponentError } from '../core/errors';
// import fetch from 'node-fetch'; // Uncomment if using node-fetch
// MARK: - ApiExtractor
export class ApiExtractor<TOutput> implements IExtractor<TOutput> {
private config: ApiSourceConfig;
constructor(config: ApiSourceConfig) {
if (!config.url) {
throw new ComponentError('ApiExtractor requires "url" in config.');
}
this.config = config;
this.config.method = config.method || 'GET';
}
// MARK: - extract
async extract(context: PipelineContext): Promise<DataSource<TOutput>> {
context.logger.info(`Extracting data from API: ${this.config.method} ${this.config.url}`);
try {
const response = await fetch(this.config.url, {
method: this.config.method,
headers: this.config.headers,
body: this.config.body ? JSON.stringify(this.config.body) : undefined,
// Add timeout, agent, etc. if needed
});
if (!response.ok) {
const errorBody = await response.text();
throw new ComponentError(`API request failed with status ${response.status}: ${response.statusText}. Body: ${errorBody}`, 'ApiExtractor');
}
// Assume JSON response for now, add handling for other types
const data = await response.json();
// Check if the response is an array (common for list endpoints)
// or needs further unwrapping (e.g., data contained in response.data)
if (Array.isArray(data)) {
return data as TOutput[];
} else if (typeof data === 'object' && data !== null && 'results' in data && Array.isArray((data as any).results)) {
// Example: Handle paginated responses where items are in 'results' array
context.logger.warn(`API response is not an array, attempting to extract 'results' property.`);
return (data as any).results as TOutput[];
// TODO: Implement proper pagination handling if API supports it
}
else {
// Return single object as an array
context.logger.warn(`API response is not an array. Returning as single item array.`);
return [data as TOutput];
}
} catch (error: any) {
context.logger.error({ err: error, url: this.config.url }, `Error during API extraction`);
if (error instanceof ComponentError) throw error;
throw new ComponentError(`Failed to fetch data from API ${this.config.url}`, 'ApiExtractor', error);
}
}
}