← Назад к вопросам

Как обычно пишешь запросы?

1.8 Middle🔥 201 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Структура HTTP запросов на фронтенде

Я всегда использую централизованный подход к запросам через утилиту API сервиса. В современных React приложениях это обязательно, чтобы избежать дублирования кода и иметь единую точку управления ошибками, авторизацией и переиспользованием логики.

// lib/api.ts - центральный API сервис
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'https://api.prepbro.ru';

interface FetchOptions extends RequestInit {
  params?: Record<string, any>;
  token?: string;
}

export async function fetchAPI<T = any>(
  path: string,
  options: FetchOptions = {}
): Promise<T> {
  const { params, token, ...fetchOptions } = options;
  
  // Построение URL с параметрами
  const url = new URL(`${API_BASE}${path}`);
  if (params) {
    Object.entries(params).forEach(([key, value]) => {
      url.searchParams.append(key, String(value));
    });
  }
  
  // Подготовка заголовков
  const headers: HeadersInit = {
    'Content-Type': 'application/json',
    ...fetchOptions.headers,
  };
  
  if (token) {
    headers['Authorization'] = `Bearer ${token}`;
  }
  
  try {
    const response = await fetch(url.toString(), {
      ...fetchOptions,
      headers,
    });
    
    if (!response.ok) {
      throw new Error(`API error: ${response.status} ${response.statusText}`);
    }
    
    return response.json();
  } catch (error) {
    console.error(`Fetch failed for ${path}:`, error);
    throw error;
  }
}

Использование в компонентах

// hooks/useQuestions.ts - кастомный хук для запросов
import { useEffect, useState } from 'react';
import { fetchAPI } from '@/lib/api';

interface Question {
  id: string;
  title: string;
  text: string;
  profession_id: string;
}

export function useQuestions(professionId: string) {
  const [data, setData] = useState<Question[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const questions = await fetchAPI<Question[]>(
          '/api/v1/questions',
          {
            params: { profession_id: professionId },
          }
        );
        setData(questions);
      } catch (err) {
        setError(err instanceof Error ? err : new Error('Unknown error'));
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
  }, [professionId]);
  
  return { data, loading, error };
}

Правильная обработка ошибок

Очень важно правильно обрабатывать ошибки - не писать логирование на одном уровне, а потом повторять его на другом. Логика должна быть иерархичной.

// Неправильно
const response = await fetch(...);
if (!response.ok) {
  console.error('Error'); // логирование
  throw new Error(...);
}

// Потом в компоненте
try {
  const data = await api.fetch();
} catch (e) {
  console.error('Another error log'); // дублирование!
}

Правильно писать логирование в API сервисе, а в компонентах просто обрабатывать результат.

POST запросы с данными

// Пример отправки данных
await fetchAPI('/api/v1/comments', {
  method: 'POST',
  body: JSON.stringify({
    question_id: questionId,
    content: userAnswer,
  }),
});

Я всегда следую REST соглашениям, использую правильные HTTP методы (GET для чтения, POST для создания, PUT/PATCH для обновления) и структурирую код для переиспользования и тестируемости.