簡體   English   中英

使用 fp-ts 和 io-ts 獲取和映射數據

[英]Fetching and mapping data with fp-ts and io-ts

我正在努力將我獲取的數據“按摩”成我想要的形狀,使用fp-ts進行功能轉換和io-ts進行數據驗證。

我在尋找什么

我希望getSchools()返回描述出了什么問題的Error或經過驗證的School數組。 我的代碼有些工作,但問題是,如果獲取的學校數組中的一所學校未能通過驗證,那么一切都會失敗。 我只想過濾掉那些失敗的,然后返回 rest。

我到目前為止的代碼

/**
 * 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));
};

我認為您在這里有一些選項可以返回您想要返回的內容,並且我認為fp-ts / io-ts的默認行為與您想要的內容並不完全一致。

這是怎么回事

解析t.array時,只要其中一個值無法解碼,就會失敗。 在我看來,您想單獨嘗試解碼每個值而不是使用t.array

建議

我想我會改為這樣說:

import { pipe } from 'fp-ts/lib/function';
import * as ArrayFP from 'fp-ts/lib/Array';

const undecodedSchools: unknown[] = [/* ... school response */];
const schools: School[] = pipe(
  undecodedSchools,
  ArrayFP.map(schoolCodec.decode), // Array<Either<t.Errors, School>>
  ArrayFP.rights, // Takes an Array<Either<E, A>> -> Array<A>
);

這完全擺脫了這可能Either你想要的。 如果您想查看錯誤,可能值得改為:

const schools: {
  left: Error[],
  right: School[],
} = pipe(
  undecodedSchools,
  ArrayFP.map(schoolCodec.decode), // Array<Either<t.Errors, School>>
  ArrayFP.separate, // Takes an Array<Either<A, B>> -> Separated<A[], B[]>
);

這將兩種類型的事物從任一數組中分離出來。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM