Обсуждение получения данных в 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
});