Попробуйте отправить HTTP-запрос с проверкой параметров.
Если проверка параметра не удалась, выдайте ошибку «параметр недействителен» и остановите следующие выполнения.
Если code
ответа API не равно '0'
, сгенерируйте ошибку res.message
, иначе верните res
.
Я хочу использовать операторы try...catch...
в функции main
, чтобы поймать любую ошибку, упомянутую выше. И используйте правильный res.result
в блоке try
.
import * as t from 'io-ts';
import * as T from 'fp-ts/lib/Task';
import * as TE from 'fp-ts/lib/TaskEither';
import * as E from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/function';
import { failure } from 'io-ts/lib/PathReporter';
export interface ApiResponse<Result = any> {
code: string;
message: string | null;
result: Result;
}
const GetArticlesByPageRequestDTOCodec = t.type({
currentPage: t.number,
pageSize: t.number,
})
type GetArticlesByPageRequestDTO = t.TypeOf<typeof GetArticlesByPageRequestDTOCodec>;
type GetArticlesByPageQueryPayload = {
pagination: any;
};
const getArticlesByPage = async (data: GetArticlesByPageRequestDTO) => {
return {
code: '0',
message: '',
result: {
resultList: [
{ id: 1, title: 'test' },
{ id: 2, title: 'test1' },
],
totalItem: 100,
},
};
};
const getArticlesByPageTaskEither = (data: GetArticlesByPageRequestDTO) =>
TE.tryCatch<Error, ApiResponse>(
() =>
getArticlesByPage(data).then((res) => {
if (res.code !== '0') {
throw new Error(res.message);
}
return res;
}),
(reason) => new Error(String(reason)),
);
const getArticlesByPageService = ({ pagination }: GetArticlesByPageQueryPayload) => {
const reqDTO: GetArticlesByPageRequestDTO = {
pageSize: pagination.pageSize,
currentPage: pagination.current,
};
return pipe(
reqDTO,
GetArticlesByPageRequestDTOCodec.decode,
E.mapLeft((errors) => {
console.error(
`Validation failed for input: ${JSON.stringify(reqDTO, null, 2)}. Error details: ${failure(errors).join('\n')}`,
);
return new Error('parameter invalid');
}),
TE.fromEither,
TE.chain(getArticlesByPageTaskEither),
)();
};
async function main() {
try {
const res = await getArticlesByPageService({ pagination: { current: 1, pageSize: 10 } });
console.info(res.result)
} catch (e) {
console.error(e)
}
}
Но тип res
— это E.Either<Error, ApiResponse<any>>
, так как преобразовать его в тип Promise<ApiResponse<any>>
.
Когда я пытаюсь использовать res.result
, получаю ошибку:
Property 'result' does not exist on type 'Either<Error, ApiResponse<any>>'.
Property 'result' does not exist on type 'Left<Error>'
Есть несколько вариантов. Во-первых, вы можете просто сопоставить Either
в своей основной функции.
async function main() {
pipe(
await getArticlesByPageService({
pagination: { current: 1, pageSize: 10 },
}),
E.match(
(e) => console.error(e),
(res) => console.info(res.result)
)
);
}
Другой вариант — изменить функцию getArticlesByPageService
так, чтобы она возвращала TE.TaskEither<Error, ApiResponse<any>>
вместо обещания (просто удалив оценку функции в самом конце функции) и сделать что-то вроде этого.
async function main() {
await pipe(
getArticlesByPageService({
pagination: { current: 1, pageSize: 10 },
}),
TE.orElseFirst((e) => TE.fromIO(Console.error(e))),
TE.chainFirstIOK((res) => Console.log(res.result))
)();
}
Побочный эффект рекомендуется выполнять только в контейнерах IO
или Task
. Поэтому я лично предпочел бы тот.
Я забыл добавить, что вам также нужен импорт
import * as Console from "fp-ts/lib/Console";
для второго примера.