HTTP методы GET, POST, PUT, DELETE: полное руководство с примерами

← Вернуться к статьям

Введение

HTTP методы — это фундамент, на котором построен весь веб. Каждый раз, когда вы открываете страницу, отправляете форму, загружаете файл или удаляете аккаунт — за кулисами работает конкретный HTTP метод, который говорит серверу, что именно вы хотите сделать.

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

В этой статье вы узнаете:

📋 Содержание

Что такое HTTP методы

HTTP метод (HTTP verb) — это указание серверу, какое действие нужно выполнить с запрашиваемым ресурсом. Метод передаётся в первой строке HTTP-запроса:

GET /api/users HTTP/1.1
Host: example.com
Accept: application/json

Здесь GET — метод, /api/users — ресурс, к которому обращаемся.

Простая аналогия:

Представьте REST API как библиотеку. URL — это адрес книги на полке, а HTTP метод — действие, которое вы хотите с ней сделать:

Обзор всех HTTP методов

Стандарт HTTP определяет 9 методов, но в повседневной разработке API используются 5–7 из них:

Метод Действие Тело запроса Безопасный Идемпотентный
GET Получить данные Нет ✓ Да ✓ Да
POST Создать ресурс Да ✗ Нет ✗ Нет
PUT Заменить ресурс целиком Да ✗ Нет ✓ Да
PATCH Обновить часть ресурса Да ✗ Нет ✗ Нет
DELETE Удалить ресурс Нет (обычно) ✗ Нет ✓ Да
HEAD Получить заголовки (без тела) Нет ✓ Да ✓ Да
OPTIONS Узнать доступные методы Нет ✓ Да ✓ Да

GET — получение данных

GET — самый распространённый HTTP метод. Используется для получения данных с сервера без их изменения.

Характеристики GET

Примеры запросов

// Получить список пользователей
fetch('/api/users')
  .then(res => res.json())
  .then(users => console.log(users));
// GET /api/users → 200 OK

// Получить одного пользователя по ID
fetch('/api/users/42')
  .then(res => res.json())
  .then(user => console.log(user));
// GET /api/users/42 → 200 OK

// Фильтрация и пагинация через query string
fetch('/api/users?role=admin&page=2&limit=10')
  .then(res => res.json())
  .then(data => console.log(data));
// GET /api/users?role=admin&page=2&limit=10 → 200 OK

Типичные ответы

Код Ситуация
200 OK Данные найдены и возвращены
304 Not Modified Данные не изменились (используйте кэш)
404 Not Found Ресурс не найден

⚠️ GET никогда не должен изменять данные!

Антипаттерн: GET /api/users/42/delete — удаление через GET. Браузерный prefetch, поисковый краулер или кэширующий прокси может случайно вызвать этот URL и удалить данные. Для изменений используйте POST, PUT, PATCH или DELETE.

POST — создание ресурса

POST используется для создания нового ресурса на сервере. Данные передаются в теле запроса.

Характеристики POST

Примеры запросов

// Создать нового пользователя
const response = await fetch('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Иван Петров',
    email: 'ivan@example.com',
    role: 'developer'
  })
});

if (response.status === 201) {
  const newUser = await response.json();
  console.log('Создан:', newUser);
  // Заголовок Location: /api/users/43
  console.log('URL:', response.headers.get('Location'));
}

// Загрузить файл
const formData = new FormData();
formData.append('avatar', fileInput.files[0]);

await fetch('/api/users/42/avatar', {
  method: 'POST',
  body: formData
});

Типичные ответы

Код Ситуация
201 Created Ресурс успешно создан (+ заголовок Location)
400 Bad Request Невалидные данные в запросе
409 Conflict Ресурс уже существует (дублирование email)
422 Unprocessable Entity Данные не прошли валидацию

⚠️ POST не идемпотентен!

Если пользователь случайно нажмёт «Отправить» дважды — создадутся два одинаковых ресурса. Для защиты используйте idempotency key — уникальный идентификатор запроса в заголовке:

fetch('/api/payments', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': 'unique-request-id-12345'
  },
  body: JSON.stringify({ amount: 1000 })
});

PUT — полная замена ресурса

PUT заменяет ресурс целиком. Вы должны передать все поля объекта, даже те, которые не изменились.

Характеристики PUT

Примеры запросов

// Полностью заменить данные пользователя
const response = await fetch('/api/users/42', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Иван Сидоров',       // изменили
    email: 'ivan.new@example.com', // изменили
    role: 'developer',            // не изменился, но НУЖНО передать
    age: 30                       // не изменился, но НУЖНО передать
  })
});

// 200 OK — ресурс обновлён
// 201 Created — ресурс не существовал и был создан

PUT — это «заменить файл целиком»

Если вы не передадите поле age, сервер должен его обнулить или удалить. PUT — это не «обновить поля», а «вот как теперь должен выглядеть этот ресурс целиком».

PATCH — частичное обновление

PATCH обновляет только указанные поля ресурса. Передаёте только то, что хотите изменить.

Характеристики PATCH

Примеры запросов

// Обновить только email пользователя
const response = await fetch('/api/users/42', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: 'new.email@example.com'
    // Остальные поля НЕ передаём — они не изменятся
  })
});

// 200 OK — ресурс обновлён, возвращается полный объект

PUT vs PATCH — разница на примере

Допустим, у нас есть пользователь:

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

Хотим изменить только email:

✅ PATCH (правильно для частичного обновления)

// Передаём ТОЛЬКО изменённое поле
PATCH /api/users/42
{ "email": "new@example.com" }

// Результат: age и name сохранены
{
  "id": 42,
  "name": "Иван",
  "email": "new@example.com",
  "age": 30
}

❌ PUT (нужно передать ВСЁ)

// Должны передать ВСЕ поля
PUT /api/users/42
{
  "name": "Иван",
  "email": "new@example.com",
  "age": 30
}

// Если забудем age:
PUT /api/users/42
{ "email": "new@example.com" }
// age станет null!

DELETE — удаление ресурса

DELETE удаляет ресурс на сервере.

Характеристики DELETE

Примеры запросов

// Удалить пользователя
const response = await fetch('/api/users/42', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer eyJhbGciOi...'
  }
});

if (response.status === 204) {
  console.log('Пользователь удалён');
}

if (response.status === 404) {
  console.log('Пользователь не найден');
}

Типичные ответы

Код Ситуация
204 No Content Ресурс удалён, тело ответа пустое
200 OK Ресурс удалён, возвращается удалённый объект
404 Not Found Ресурс не найден (уже удалён?)
403 Forbidden Нет прав на удаление

⚠️ Soft Delete vs Hard Delete

Soft delete — помечаем запись как удалённую (поле deleted_at), но не удаляем из БД. Позволяет восстановить данные. Используется в большинстве production-систем.

Hard delete — физическое удаление из базы данных. Необратимо. Используйте только когда уверены, что данные не понадобятся (GDPR, очистка временных данных).

HEAD и OPTIONS

HEAD — получить только заголовки

HEAD идентичен GET, но сервер возвращает только заголовки без тела ответа. Полезен для:

// Проверить размер файла перед скачиванием
const response = await fetch('/api/files/report.pdf', {
  method: 'HEAD'
});

const fileSize = response.headers.get('Content-Length');
console.log(`Размер файла: ${(fileSize / 1024 / 1024).toFixed(2)} МБ`);

// Проверить, существует ли ресурс
const exists = response.status === 200;

OPTIONS — узнать доступные методы

OPTIONS возвращает информацию о доступных методах для данного URL. Активно используется в CORS preflight-запросах — браузер автоматически отправляет OPTIONS перед кросс-доменными запросами.

OPTIONS /api/users HTTP/1.1
Host: api.example.com

HTTP/1.1 204 No Content
Allow: GET, POST, OPTIONS
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

Идемпотентность и безопасность

Два ключевых свойства HTTP методов, которые влияют на архитектуру API, кэширование и обработку ошибок.

Безопасные методы (Safe)

Безопасный метод не изменяет состояние сервера. Его можно вызывать сколько угодно раз без побочных эффектов.

Безопасные: GET, HEAD, OPTIONS

Браузеры, поисковые роботы и CDN могут свободно вызывать безопасные методы. Именно поэтому GET не должен изменять данные — поисковый робот Google может зайти на GET /api/users/42/delete и случайно удалить пользователя.

Идемпотентные методы (Idempotent)

Идемпотентный метод при повторном вызове с теми же данными даёт тот же результат. Состояние сервера после N вызовов то же, что и после одного.

Метод Идемпотентен? Объяснение
GET ✓ Да Чтение не меняет данные — сколько ни читай, результат один
POST ✗ Нет Каждый вызов создаёт новый ресурс (2 вызова = 2 пользователя)
PUT ✓ Да Замена одним и тем же объектом — результат один и тот же
PATCH ✗ Нет* Формально нет (зависит от реализации), но на практике обычно да
DELETE ✓ Да Удалить дважды — ресурс всё равно удалён (второй вызов = 404)

⚠️ Почему идемпотентность важна?

Сеть ненадёжна. Если запрос «завис» и клиент не получил ответ — нужно повторить. С идемпотентным методом повторный вызов безопасен. С POST — может создать дубликат.

Пример: Клиент отправил PUT /api/users/42, сервер обработал, но ответ потерялся в сети. Клиент повторяет запрос — результат тот же, данные не испорчены. С POST /api/payments без idempotency key — деньги спишутся дважды.

CRUD-операции и HTTP методы

CRUD (Create, Read, Update, Delete) — четыре базовых операции с данными. Каждая операция соответствует HTTP методу:

CRUD HTTP метод URL (пример) Описание
Create POST POST /api/users Создать нового пользователя
Read (список) GET GET /api/users Получить список пользователей
Read (один) GET GET /api/users/42 Получить пользователя #42
Update (полностью) PUT PUT /api/users/42 Заменить пользователя #42 целиком
Update (частично) PATCH PATCH /api/users/42 Обновить поля пользователя #42
Delete DELETE DELETE /api/users/42 Удалить пользователя #42

Правила именования URL в REST API:

Полные примеры на трёх языках

JavaScript (fetch API)

const API_BASE = 'https://api.example.com';

// GET — получить список
async function getUsers() {
  const res = await fetch(`${API_BASE}/users`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// POST — создать
async function createUser(userData) {
  const res = await fetch(`${API_BASE}/users`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData)
  });
  if (res.status !== 201) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// PUT — заменить целиком
async function replaceUser(id, userData) {
  const res = await fetch(`${API_BASE}/users/${id}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData)
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// PATCH — обновить частично
async function updateUser(id, fields) {
  const res = await fetch(`${API_BASE}/users/${id}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(fields)
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// DELETE — удалить
async function deleteUser(id) {
  const res = await fetch(`${API_BASE}/users/${id}`, {
    method: 'DELETE'
  });
  if (res.status !== 204) throw new Error(`HTTP ${res.status}`);
  return true;
}

// Использование
const users = await getUsers();
const newUser = await createUser({ name: 'Иван', email: 'ivan@test.ru' });
await updateUser(newUser.id, { email: 'new@test.ru' });
await deleteUser(newUser.id);

Python (requests)

import requests

API_BASE = 'https://api.example.com'
headers = {'Content-Type': 'application/json'}

# GET — получить список
response = requests.get(f'{API_BASE}/users')
users = response.json()

# POST — создать
response = requests.post(f'{API_BASE}/users', json={
    'name': 'Иван',
    'email': 'ivan@test.ru'
}, headers=headers)

if response.status_code == 201:
    new_user = response.json()
    print(f'Создан: {new_user["id"]}')

# PUT — заменить целиком
response = requests.put(f'{API_BASE}/users/42', json={
    'name': 'Иван Сидоров',
    'email': 'ivan@test.ru',
    'role': 'admin'
}, headers=headers)

# PATCH — обновить частично
response = requests.patch(f'{API_BASE}/users/42', json={
    'email': 'new@test.ru'
}, headers=headers)

# DELETE — удалить
response = requests.delete(f'{API_BASE}/users/42')
if response.status_code == 204:
    print('Удалено')

PHP (cURL)

<?php

$apiBase = 'https://api.example.com';

function apiRequest(string $url, string $method = 'GET', ?array $data = null): array
{
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
    ]);

    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json'
        ]);
    }

    $response   = curl_exec($ch);
    $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    return [
        'status' => $statusCode,
        'data'   => json_decode($response, true),
    ];
}

// GET — список
$result = apiRequest("$apiBase/users");
$users = $result['data'];

// POST — создать
$result = apiRequest("$apiBase/users", 'POST', [
    'name'  => 'Иван',
    'email' => 'ivan@test.ru',
]);
// $result['status'] === 201

// PUT — заменить
$result = apiRequest("$apiBase/users/42", 'PUT', [
    'name'  => 'Иван Сидоров',
    'email' => 'ivan@test.ru',
    'role'  => 'admin',
]);

// PATCH — обновить
$result = apiRequest("$apiBase/users/42", 'PATCH', [
    'email' => 'new@test.ru',
]);

// DELETE — удалить
$result = apiRequest("$apiBase/users/42", 'DELETE');
// $result['status'] === 204

Частые ошибки

❌ Ошибка 1: Использовать GET для изменения данных

GET /api/users/42/delete    ← НИКОГДА так не делайте
GET /api/users/42/activate  ← тоже плохо
GET /api/send-email?to=...  ← и так нельзя

GET должен только читать. Для действий используйте POST или соответствующий метод.

❌ Ошибка 2: POST для всего

Некоторые API используют только POST для всех операций, передавая действие в теле запроса. Это нарушает принципы REST и ломает кэширование, семантику и инструменты мониторинга.

POST /api → { "action": "getUser", "id": 42 }     ← RPC, не REST
POST /api → { "action": "deleteUser", "id": 42 }  ← антипаттерн

❌ Ошибка 3: PUT вместо PATCH для частичного обновления

Если нужно обновить одно поле — используйте PATCH. PUT с неполным набором полей обнулит пропущенные значения.

✅ Правильный выбор метода — шпаргалка

Нужно Метод Пример
Получить данные GET GET /api/users
Создать новый ресурс POST POST /api/users
Заменить ресурс целиком PUT PUT /api/users/42
Обновить пару полей PATCH PATCH /api/users/42
Удалить ресурс DELETE DELETE /api/users/42
Проверить заголовки HEAD HEAD /api/files/report.pdf
Узнать разрешённые методы OPTIONS OPTIONS /api/users

FAQ

❓ В чём разница между PUT и PATCH?

Ответ: PUT заменяет ресурс целиком — вы должны передать все поля объекта. Если пропустите поле — оно будет обнулено. PATCH обновляет только указанные поля — остальные остаются без изменений.

PUT  /users/42 → { name, email, age } — ВСЕ поля обязательны
PATCH /users/42 → { email }           — только изменённое поле

❓ Почему GET-запросы не должны изменять данные?

Ответ: GET — безопасный метод по спецификации HTTP. Браузеры, прокси и CDN могут кэшировать GET-запросы и повторять их автоматически. Если GET будет удалять или изменять данные, то:

  • Поисковый робот Google, обходя ваш API, может случайно стереть данные
  • Браузерный prefetch загрузит URL до клика — и выполнит действие
  • Кэширующий прокси может повторить запрос

❓ Что такое идемпотентность HTTP методов?

Ответ: Идемпотентный метод — тот, который при повторном вызове с теми же параметрами даёт тот же результат. Состояние сервера не меняется от повторных вызовов.

  • GET — идемпотентен: сколько ни читай, результат один
  • PUT — идемпотентен: замена тем же объектом = тот же результат
  • DELETE — идемпотентен: удалить дважды = ресурс всё равно удалён
  • POST — НЕ идемпотентен: 2 вызова = 2 новых ресурса

❓ Когда использовать POST вместо PUT?

Ответ:

  • POST — когда сервер сам назначает идентификатор нового ресурса: POST /api/users → сервер создаёт пользователя с id=42
  • PUT — когда клиент знает идентификатор и хочет создать или заменить конкретный ресурс: PUT /api/users/42 → создать/заменить пользователя с id=42
POST /api/users         → Создай пользователя (ID назначит сервер)
PUT  /api/users/42      → Создай/замени пользователя #42 (ID знает клиент)

Заключение

📝 Сводная таблица HTTP методов

Метод CRUD Тело Идемпотентный Типичный ответ
GET Read Нет 200 OK
POST Create Да 201 Created
PUT Replace Да 200 OK
PATCH Update Да ✗* 200 OK
DELETE Delete Нет 204 No Content

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

💡 Три главных правила:

  1. GET — только для чтения, никогда не изменяйте данные через GET
  2. PATCH для частичного обновления, PUT — только когда нужно заменить ресурс целиком
  3. Помните об идемпотентности — для POST используйте idempotency key, чтобы избежать дубликатов

🎯 Тестируйте все HTTP методы с LightBox API

Хотите проверить, как ваше приложение работает с GET, POST, PUT, PATCH и DELETE?

LightBox API позволяет создать Mock API с поддержкой всех HTTP методов — настройте разные ответы для каждого метода и тестируйте CRUD-операции.

Попробовать бесплатно →

Статья опубликована: 23 февраля 2026
Автор: LightBox API Team