EvolCode
треки/Сервер и продакшн·01 / 08
6 мин чтения

HTTP и REST на пальцах

HTTP — язык общения браузера и сервера. REST — соглашение «как именно строить URL и какие методы использовать». Это фундамент любого API. Понимаешь это — понимаешь любой бэкенд.

Запрос и ответ

Браузер шлёт запрос: метод (GET, POST...), URL, заголовки, опционально тело. Сервер отвечает: status code, заголовки, тело. Вот и весь HTTP. Заголовки — мета-информация (Content-Type, Authorization, Cookie). Тело — основные данные (JSON чаще всего). Открой DevTools → Network → ты видишь каждый такой запрос своего сайта.

Методы

GET — «дай данные» (получить пользователя). POST — «прими и обработай» (создать заказ). PUT — «замени целиком». PATCH — «частичное обновление». DELETE — «удали». GET идемпотентен и без тела (параметры в URL). POST/PUT/PATCH несут JSON в теле. Это конвенция REST — большинство API ей следуют. ИИ генерирует код по этой конвенции.

Status codes

200 — OK. 201 — Created (после POST). 204 — No Content (после DELETE). 400 — Bad Request (клиент послал фигню). 401 — Unauthorized (нет авторизации). 403 — Forbidden (есть авторизация, но прав не хватает). 404 — Not Found. 409 — Conflict (например уже существует). 429 — Too Many Requests. 500 — Internal Server Error. 502 — Bad Gateway. Запомни хотя бы 200, 400, 401, 404, 500 — этого хватит на 80% случаев.

REST URL — конвенция

GET /users — список пользователей. GET /users/42 — один. POST /users — создать. PUT /users/42 — заменить. DELETE /users/42 — удалить. Глаголов в URL быть НЕ должно: GET /getUser — антипаттерн, метод GET сам говорит «получить». Вложенность для отношений: GET /users/42/orders — заказы юзера 42.

CORS — частая ловушка

Браузер не пускает JS-код одного сайта дёргать API другого без явного разрешения. Это защита от XSS. Если твой фронтенд (example.com) шлёт fetch на api.other.com — нужно чтобы api.other.com отдал заголовок Access-Control-Allow-Origin. С СВОИМ бэкендом (на том же домене или /api роуте) проблем нет. С чужим — либо просишь поддержку, либо проксируешь через свой сервер.

примерtypescript
// === КЛИЕНТ ===
const API = 'https://example.com/api';

// GET — получить список
const r1 = await fetch(`${API}/users`);
const users = await r1.json();          // [{id:1, name:"Alex"}, ...]

// GET — один
const r2 = await fetch(`${API}/users/42`);
if (r2.status === 404) console.log('Не нашли');
const user = await r2.json();

// POST — создать (тело — JSON)
const r3 = await fetch(`${API}/users`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Иван', email: 'i@e.com' }),
});
if (r3.status === 201) {
  const created = await r3.json();      // {id:43, ...}
}

// PUT — заменить целиком
await fetch(`${API}/users/42`, {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Алексей', email: 'a@e.com' }),
});

// PATCH — обновить частично
await fetch(`${API}/users/42`, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: 'new@e.com' }),
});

// DELETE — удалить
const r4 = await fetch(`${API}/users/42`, { method: 'DELETE' });
if (r4.status === 204) console.log('Удалён');


// === СЕРВЕР (Next.js App Router) ===

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

export async function GET() {
  const users = await db.user.findMany();
  return NextResponse.json(users);
}

export async function POST(req: Request) {
  const body = await req.json();
  if (!body.name || !body.email) {
    return NextResponse.json(
      { error: 'name и email обязательны' },
      { status: 400 }
    );
  }
  const created = await db.user.create({ data: body });
  return NextResponse.json(created, { status: 201 });
}

// app/api/users/[id]/route.ts
export async function GET(req: Request, { params }: { params: { id: string } }) {
  const user = await db.user.findUnique({ where: { id: params.id } });
  if (!user) {
    return NextResponse.json({ error: 'Не найден' }, { status: 404 });
  }
  return NextResponse.json(user);
}

export async function DELETE(req: Request, { params }: { params: { id: string } }) {
  await db.user.delete({ where: { id: params.id } });
  return new Response(null, { status: 204 });   // No Content
}

Полный CRUD клиент-сервер на REST

главное
  • 01HTTP = метод + URL + заголовки + (опционально) тело
  • 02GET читает (без тела), POST создаёт, PUT заменяет, PATCH обновляет, DELETE удаляет
  • 03Status: 2xx — успех, 4xx — ошибка клиента, 5xx — ошибка сервера
  • 04REST URL — без глаголов: /users (не /getUsers); /users/42/orders для отношений
  • 05JSON в теле — стандарт; не забудь Content-Type: application/json
  • 06CORS — браузер блокирует кросс-доменные запросы без явного разрешения сервера
  • 07DevTools → Network — твой главный инструмент для отладки HTTP
проверь себя
01Сервер вернул 401. В чём проблема?
02Какой метод правильный для «обновить только email пользователя»?
03CORS-ошибка при fetch с фронтенда на чужой API. Что НЕ поможет?
следующий урок: Базы данных: SQLite vs Postgres vs «что попало»