import {
registerPlugin,
HandledRoute,
httpGetJson,
routeSplit,
renderTemplate,
logError,
yellow
} from '@scullyio/scully';
interface JsonRouteConfig {
type: string;
[param: string]: {
url: string;
property?: string;
resultsHandler?: (data: any) => any;
headers?: { [key: string]: string };
};
}
const jsonRoutePlugin = async (
route: string,
conf: JsonRouteConfig
): Promise<HandledRoute[]> => {
try {
// Parse route to extract parameters
const { params, createPath } = routeSplit(route);
// Verify all parameters have configuration
const missingParams = params.filter(
param => !conf.hasOwnProperty(param.part)
);
if (missingParams.length > 0) {
logError(
`Missing config for parameters (${missingParams.join(',')}) ` +
`in route: ${route}. Skipping.`
);
return [{ route, type: conf.type }];
}
// Helper to load data for a parameter
const loadData = async (param, context = {}): Promise<any[]> => {
const url = renderTemplate(conf[param.part].url, context).trim();
const rawData = await httpGetJson(url, {
headers: conf[param.part].headers,
});
// Apply custom results handler if provided
const processedData = conf[param.part].resultsHandler
? conf[param.part].resultsHandler(rawData)
: rawData;
// Extract specific property if configured
return conf[param.part].property
? processedData.map(row => row[conf[param.part].property])
: processedData;
};
// Build routes by reducing over parameters
const routes = await params.reduce(
async (total, param, index) => {
const foundRoutes = await total;
if (index === 0) {
// First iteration: create initial route data
return (await loadData(param)).map(r => [r]);
}
// Subsequent iterations: expand routes
return Promise.all(
foundRoutes.map(async (data) => {
// Build context from previous parameters
const context = data.reduce((ctx, r, x) => {
return { ...ctx, [params[x].part]: r };
}, {});
// Load additional data with context
const additionalRoutes = await loadData(param, context);
// Combine with existing data
return additionalRoutes.map(r => [...data, r]);
})
).then(chunks => chunks.flat());
},
Promise.resolve([])
);
// Transform to HandledRoute objects
return routes.map((routeData: string[]) => ({
route: createPath(...routeData),
type: conf.type,
}));
} catch (error) {
logError(`Could not fetch data for route "${yellow(route)}"`
, error);
return [{ route, type: conf.type }];
}
};
registerPlugin('router', 'json', jsonRoutePlugin);