EvolCode
треки/API и .env·05 / 05
8 мин чтения

Подключаем первый API: пошагово

Теория теорией — но пока вы своими руками не подключите API, оно не «застрянет в голове». Соберём минимальный, но честный пример: серверный API-роут в Next.js, который вызывает OpenAI, корректно обрабатывает ошибки, и понятно сообщает клиенту что не так.

План

Шаг 1 — кладём ключ в .env (OPENAI_API_KEY=sk-proj-...) и проверяем, что .env в .gitignore. Шаг 2 — создаём файл app/api/ask/route.ts с функцией POST. Шаг 3 — внутри функции читаем тело запроса, берём ключ из process.env, шлём fetch на OpenAI. Шаг 4 — возвращаем ответ или вменяемую ошибку. Шаг 5 — на клиенте кнопка вызывает /api/ask, не OpenAI напрямую. Никакой магии.

Что такое route handler

В Next.js App Router любой файл app/api/.../route.ts с экспортируемой функцией POST (или GET) автоматически становится HTTP-роутом. Зашли по адресу /api/ask методом POST — выполнилась эта функция. Внутри она получает Request, должна вернуть Response. Это серверный код — нет window, нет document, можно читать process.env, можно ходить в БД, можно делать ВСЁ что угодно. То же самое в SvelteKit (+server.ts), Remix (action), Express (app.post(...)) — общая идея.

Обработка ошибок

Главная ошибка новичков — забыть про статусы. OpenAI вернул 401? Значит ваш ключ невалидный — скажите клиенту чётко, не «что-то пошло не так». Вернул 429? Превышен лимит — пусть пользователь подождёт. 500? У них упало — попробуйте позже. Каждый класс ошибки → свой код в вашем ответе клиенту: 400 = клиент сделал что-то не так, 401 = не авторизован, 502 = upstream-сервис ответил плохо, 500 = вы накосячили. И всегда console.error на сервере — иначе не отдебажите.

Где смотреть, если не работает

1) Терминал, в котором запущен

$ npm run dev

там логи серверного кода и ваши console.error. 2) DevTools → Network в браузере: видно запрос /api/ask, его статус, тело ответа. 3) Если 401 — точно ли ключ из дашборда (часто копируют со скрытыми пробелами)? Перезапускали dev-сервер после правки .env? 4) Если CORS-ошибка — вы случайно зовёте OpenAI с клиента, не с сервера. 5) Если ничего не происходит — проверьте, что метод POST, а не GET (типичная ошибка).

примерtsx
// Полный пример: подключаем OpenAI через серверный роут.

// .env
OPENAI_API_KEY=sk-proj-твойреальныйключ
DAILY_REQUEST_LIMIT=50

// app/api/ask/route.ts
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
  const { prompt } = await req.json();

  if (!prompt || prompt.length < 2) {
    return NextResponse.json({ error: 'Промпт пустой' }, { status: 400 });
  }

  try {
    const r = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini',
        messages: [{ role: 'user', content: prompt }],
      }),
    });

    if (!r.ok) {
      const err = await r.text();
      console.error('OpenAI error:', r.status, err);
      // 401 = неверный ключ
      // 429 = превышен лимит
      // 500 = проблема на стороне OpenAI
      return NextResponse.json(
        { error: `OpenAI ответил ${r.status}` },
        { status: 502 }
      );
    }

    const data = await r.json();
    return NextResponse.json({ answer: data.choices[0].message.content });
  } catch (e) {
    console.error('Network error:', e);
    return NextResponse.json({ error: 'Сетевая ошибка' }, { status: 500 });
  }
}

// app/page.tsx
'use client';
import { useState } from 'react';

export default function Page() {
  const [answer, setAnswer] = useState('');

  async function ask() {
    const r = await fetch('/api/ask', {
      method: 'POST',
      body: JSON.stringify({ prompt: 'Объясни что такое API' }),
    });
    const data = await r.json();
    setAnswer(data.answer ?? data.error);
  }

  return (
    <>
      <button onClick={ask}>Спросить ИИ</button>
      <p>{answer}</p>
    </>
  );
}

Полный рабочий пример: серверный роут + клиентская кнопка

главное
  • 01Файл app/api/имя/route.ts с функцией POST = HTTP-роут на /api/имя
  • 02Внутри роута доступны process.env.* и любые серверные операции
  • 03Клиент дёргает свой /api/ask, а уже роут идёт во внешний сервис
  • 04Обрабатывайте статусы upstream-сервиса (401/429/500) и возвращайте клиенту понятные коды
  • 05Логи серверного кода смотрите в терминале с npm run dev
  • 06Network-tab в DevTools показывает все запросы клиента — главный инструмент дебага
  • 07После правки .env — обязательный перезапуск dev-сервера
проверь себя
01Где появятся `console.error("Network error:", e)` из серверного route handler?
02Клиент шлёт fetch("/api/ask"), но в DevTools видно ошибку CORS. В чём дело?
03Подключаете API сторонний сервис, а в ответ постоянно 401. С чего начать?
← к треку