I'm currently facing a challenge in shaping my fetched data into the desired format, utilizing fp-ts
for functional transformation and io-ts
for data validation.
My Objective
The goal is for getSchools()
to either deliver an Error
detailing any issues encountered, or provide an array of validated School
objects. While my current code somewhat functions, it fails entirely if just one school in the fetched array does not pass validation. Ideally, I would prefer to filter out the invalid schools and return the valid ones.
Status of My Code
/**
* API route for all Schools
*/
export default async (_: NextApiRequest, res: NextApiResponse<unknown>) => {
return new Promise(
pipe(
getSchools(),
fold(
(e) => of(res.status(400).end(e.message)),
(v) => of(res.status(200).json(v))
)
)
);
};
/**
* Handler for fetching Schools
*/
export function getSchools(): TaskEither<Error, Array<School>> {
return pipe(
fetch(schoolQuery(schoolQueryBody)),
chain(mapToSchools),
chain(decode(t.array(School)))
);
}
function mapToSchools(
inputs: Array<any>
): TaskEither<Error, Array<School>> {
try {
return right(inputs.map(mapToSchool));
} catch (e) {
return left(new Error("Could not map input to school"));
}
}
export function mapToSchool(input: any): School // Can throw Error
export const schoolQueryBody = `...`;
function fetch(query: string): TaskEither<Error, unknown>
export function decodeError(e: t.Errors): Error {
const missingKeys = e.map((e) => e.context.map(({ key }) => key).join("."));
return new Error(`Missing keys: ${missingKeys}`);
}
export const decode = <I, A>(Type: t.Decoder<I, A>) => (
res: I
): TaskEither<Error, A> => {
return pipe(fromEither(Type.decode(res)), mapLeft(decodeError));
};