CRUD через HTTP

CRUD через HTTP

Мы знаем REST-принципы и JSON-формат. Теперь соберём их вместе и разберём, как HTTP-методы отображаются на четыре базовые операции с данными: Create, Read, Update, Delete (CRUD). Это самый частый паттерн в веб-разработке.

Что такое CRUD

CRUD — аббревиатура четырёх операций, применимых к любому хранилищу данных:

ОперацияHTTP-методURLЧто делаетСтатус успеха
CreatePOST/usersСоздать новый ресурс201 Created
Read (list)GET/usersПолучить список200 OK
Read (single)GET/users/42Получить один ресурс200 OK
UpdatePUT/PATCH/users/42Обновить ресурс200 OK
DeleteDELETE/users/42Удалить ресурс204 No Content

Важно: HTTP-метод определяет действие, URL идентифицирует ресурс. Не нужно писать /users/create или /users/delete/42 — метод уже говорит, что делать.

Create: POST /users

Клиент отправляет POST-запрос с телом, содержащим данные нового ресурса:

POST /users HTTP/1.1
Content-Type: application/json

{
  "name": "Иван",
  "email": "ivan@example.com"
}

Сервер создаёт ресурс и возвращает:

HTTP/1.1 201 Created
Location: /users/142
Content-Type: application/json

{
  "id": 142,
  "name": "Иван",
  "email": "ivan@example.com",
  "createdAt": "2026-04-30T12:00:00Z"
}

Ключевые моменты:

  • Статус 201 Created (не 200!), чтобы клиент понимал — ресурс создан.
  • Заголовок Location содержит URL нового ресурса.
  • Сервер добавляет поля, которых не было в запросе (id, дата создания).

POST не обязан возвращать тело, но на практике возвращает созданный объект — клиенту нужен id.

Read (list): GET /users

GET для коллекции возвращает массив ресурсов:

GET /users HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

[
  {"id": 1, "name": "Иван"},
  {"id": 2, "name": "Мария"},
  {"id": 3, "name": "Алексей"}
]

Для больших коллекций добавляют пагинацию через query-параметры:

GET /users?page=2&limit=20

HTTP/1.1 200 OK

{
  "data": [
    {"id": 21, "name": "..."},
    ...
  ],
  "total": 150,
  "page": 2,
  "limit": 20
}

Read (single): GET /users/42

GET для конкретного элемента возвращает один объект:

GET /users/42 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 42,
  "name": "Иван",
  "email": "ivan@example.com",
  "orders": "/users/42/orders"
}

Если ресурс не существует — 404 Not Found:

HTTP/1.1 404 Not Found
Content-Type: application/json

{"error": "User not found"}

Update: PUT vs PATCH

Для обновления есть два метода с разной семантикой:

  • PUT — заменить ресурс ЦЕЛИКОМ. Если пропустить поле, оно удалится (или сбросится на значение по умолчанию).
  • PATCH — частичное обновление. Отправляются только поля, которые нужно изменить.
PUT /users/42
Content-Type: application/json

{"name": "Иван", "email": "new@example.com"}  ← Все поля обязательны

PATCH /users/42
Content-Type: application/json

{"email": "new@example.com"}  ← Только что меняется

На практике PATCH используют чаще — он безопаснее (нельзя случайно стереть поля). PUT строже и требует от клиента полного представления ресурса.

Delete: DELETE /users/42

Удаление самое простое — метод DELETE, без тела:

DELETE /users/42 HTTP/1.1

HTTP/1.1 204 No Content

204 No Content — стандартный статус для успешного DELETE (тела ответа нет). Но некоторые API возвращают 200 с удалённым объектом в теле.

Повторный DELETE на тот же URL должен возвращать 404 Not Found (ресурс уже удалён) или 204 No Content (идемпотентность: результат тот же, ресурса нет). На практике чаще 404.

Идемпотентность методов

Идемпотентность — важное свойство HTTP-методов. Метод идемпотентен, если повторный запрос даёт тот же результат, что и первый:

МетодИдемпотентен?Повторный вызов
GETДаВернёт те же данные
PUTДаЗаменит теми же данными = тот же результат
DELETEДаРесурс уже удалён = тот же результат (404 или 204)
POSTНетСоздаст ещё один ресурс!

Это важно для надёжности: если клиент не получил ответ (сеть моргнула), он может безопасно повторить GET/PUT/DELETE. POST повторять опасно — можно создать дубликат.

CRUD в реальном API: пример

Полный цикл управления пользователем:

// Создать
const createResp = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Иван', email: 'ivan@example.com' })
});
const newUser = await createResp.json();  // { id: 142, name: 'Иван', ... }

// Прочитать
const user = await fetch(`/api/users/${newUser.id}`).then(r => r.json());

// Обновить
await fetch(`/api/users/${newUser.id}`, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Иван Петров' })
});

// Удалить
await fetch(`/api/users/${newUser.id}`, { method: 'DELETE' });

Проверь себя

  1. Как отличить запрос на создание от запроса на чтение списка, если URL один и тот же (/users)?
  2. Почему POST неидемпотентен, а PUT идемпотентен?
  3. Какой статус-код обычно возвращается при успешном DELETE?
<details> <summary>Ответы</summary>
  1. По HTTP-методу: POST — создать, GET — прочитать список. Один URL, разные методы — разные действия.
  2. POST каждый раз создаёт новый ресурс (два POST → два пользователя). PUT заменяет ресурс целиком — два одинаковых PUT дают одинаковый результат.
  3. 204 No Content — успешное удаление, тела ответа нет. Некоторые API возвращают 200 с удалённым объектом.
</details>

Что унести с урока

  • CRUD: Create (POST), Read (GET), Update (PUT/PATCH), Delete (DELETE) — четыре базовые операции.
  • HTTP-метод определяет действие, URL определяет ресурс. Метод + URL = операция.
  • PUT — полная замена, PATCH — частичное обновление.
  • GET/PUT/DELETE идемпотентны — можно безопасно повторять. POST — нет.

В завершающем уроке модуля разберём, как читать документацию API — где найти эндпоинты, форматы запросов и ответов, и как тестировать API не написав ни строчки кода.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике