Обсуждение получения данных в Nextjs: Добавление типов в запросы и ответы и использование fetch API

Context Я создаю веб-приложение с помощью nextjs и пользовательского бэкенда на Django Python, и мне трудно найти чистый способ делать API-запросы к моему бэкенду из Nextjs. Я ищу способ централизовать логику для функции fetch, добавив при этом безопасность типов для тела запроса и ответов.

Текущий подход

const api = {
  get: async function (url: string): Promise<any> {
    console.log("get", url);

    return new Promise((resolve, reject) => {
      fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}${url}`, {
        method: "GET",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
        cache: "no-store",
      })
        .then((response) => response.json())
        .then((json) => {
          console.log("Response:", json);

          resolve(json);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },
  post: async function (url: string, data: any): Promise<any> {
    console.log("post", url, data);

    return new Promise((resolve, reject) => {
      fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}${url}`, {
        method: "POST",
        body: JSON.stringify(data),
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      })
        .then((response) => response.json())
        .then((json) => {
          console.log("Response:", json);

          resolve(json);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },
}

При таком подходе я централизую логику для get и post запросов в том смысле, что теперь я могу просто импортировать api и вызвать api.post/get, чтобы сделать запрос к бэкенду. Однако мне не нравится повторять код для будущих методов, таких как patch и delete. Самая большая проблема, которую я испытываю при таком подходе, - это потеря безопасности типов, поскольку GET и POST возвращают данные типа any, а POST принимает данные типа any... no bueno.

Обработчики маршрутов Я также просмотрел документацию Nextjs по обработчикам маршрутов route handlers, но мне кажется, что это наталкивается на те же проблемы: Либо вам придется повторять код для fetch каждый раз, когда вы хотите сделать запрос к бэкенду, либо вы централизуете эту логику, но тогда теряете безопасность типов. Мне также не нравится создавать целый файл для GET-запроса.

Обсуждение Хотя я был бы признателен за ответ конкретно на эту проблему, в целом, как вы, ребята, создаете чистый API в Nextjs, который повторно использует код для fetch API, добавляет безопасность типов и легко читается/чистится?

Для обеспечения безопасности типов можно использовать шаблонные литеральные типы и дженерики на основе URL:

type User = {
    name: string;
}

type GetUserByIdUrl = `/users/${number}`;

type RequestMap = {
    "/users": User[];
    [k: GetUserByIdUrl]: User;
}

function httpGet<T extends keyof RequestMap>(url: T): Promise<RequestMap[T]> {
    // ...
};

httpGet("/users").then(res => {
    type test1 = typeof res; // User[]
});

httpGet("/users/1").then(res => {
    type test2 = typeof res; // User
});
Вернуться на верх