NextJS - Route Handler 中错误处理的类型问题

问题描述 投票:0回答:1

我有一个如下所示的路线处理程序

应用程序/api/交易/route.ts

import { NextRequest, NextResponse } from "next/server";
import { AxiosError } from "axios";
import axios from "../axios";
import { AxiosResponse } from "axios";
import { Transaction } from "../../../types";

interface Error {
  message: string[];
  statusCode: number;
}

export async function GET(request: NextRequest) {
  try {
    const transactionsRes: AxiosResponse<Transaction[]> = await axios.get(
      `/transactions`
    );

    return NextResponse.json(transactionsRes.data);
  } catch (error) {
    const axiosError = error as AxiosError<Error>;
    return NextResponse.json(
      { error: axiosError?.response?.data.message },
      { status: axiosError?.response?.data.statusCode }
    );
  }
}

MyComponent.tsx

export const MyComponent = async() => {
  const raw = await fetch('api/transaction');
  const transactions: Transaction[] = await raw.json();
  if (transactions.error) {
    throw new Error(transactions.error);
  }
  ...
}

我还有一个

error.tsx
作为错误边界来捕获错误

我发现的问题是,当我以这种方式处理错误时,我可能需要像这样输入

transaction
响应。

const transactions: Transaction[] | TransactionError = await raw.json();

如果我这样做的话,这种类型对我来说似乎很混乱并且无法扩展。只是想知道 nextjs 中处理错误的最佳结构是什么?

javascript reactjs typescript next.js axios
1个回答
0
投票

如果错误的数据以 json 形式包含在响应正文中,则获取它的唯一方法是

raw.json()
,因此不会有神奇的方法来处理它。您的方法是正确的,但我可以向您展示一些使用数据的技巧。

1. Type-guard(缩小)

您可以检查属性和

typeof
数据是否完全适合类型划分,如下所示:

if(Array.isArray(transactions)) {
    transactions.map(() => {}) // works fine and type-friendly
} else {
    transactions.errorMessage // works fine and type-friendly
}

或者如果你想在很多地方这样做,甚至更干净:

function isTransactionError(data: unknown) data is TransactionError {
    return data && data.errorMessage
}

if(isTransactionError(transactions)) {
    transactions.errorMessage // works fine
} else {
    transactions.map(() => {}) // works fine
}

您可以在这里阅读有关类型保护的更多信息:https://www.typescriptlang.org/docs/handbook/2/narrowing.html

2.将您的数据和错误放在单独的属性中(如果后端是您的)

您可以在单独的属性中返回数据和错误对象。大多数框架和 API 工具(例如 graphql)都做同样的事情。

// success:
{
    data: [{...}, {...}], // here is your transactions
    error: null
}

// failure:
{
    data: null,
    error: {...}
}

然后你也可以对其进行类型保护:

result.data?.map(() => {})

result.error?.errorMessage
3.另一种检查响应是否错误的方法(
raw.ok
)

Mozilla 说这里

Response 接口的

ok
只读属性包含一个布尔值,指示响应是否成功(状态范围为 200-299)。

您可以这样使用它:

if(raw.ok) {
    console.log("Success!")
} else {
    console.log("Error :(")
}

但是,它对类型不友好。那么让我们来实现吧:

type ResponsePayload<TResult, TError = unknown> = {
    data: TResult | null;
    error: TError | null;
}

type ResponseWithPayload<TResult, TError = unknown> = Response & {
    payload: ResponsePayload<TResult, TError>
}

async function withTypes<TResult, TError = unknown>(response: Promise<Response> | Response) {
   const resp = await response as ResponseWithPayload<TResult, TError>;

   const payload = await resp.json();

   if(resp.ok) {
      resp.payload = {
         data: payload,
         error: null,
      }
   } else {
      resp.payload = {
         data: null,
         error: payload,
      }
   }

   return resp;
}

并像这样使用它:

// example 1
const resp = await withTypes<Transaction[], TransactionError>(fetch("..."))

resp.payload.data?.map(() => {});
resp.payload.error?.errorMessage;

// example 2

const resp2 = await fetch("...");
const { payload } = await withTypes<Transaction[]>(resp2)

payload.data?.map(() => {});
© www.soinside.com 2019 - 2024. All rights reserved.