Разница POST и PUT в REST API: когда использовать
Разница между HTTP POST и PUT по RFC 2616: POST для создания подчиненного ресурса в коллекции (сервер генерирует URI), PUT — идемпотентная замена или создание по точному пути. Рекомендации по дизайну REST API с примерами и статусами.
В чем разница между методами HTTP POST и PUT, и когда каждый из них следует использовать для создания ресурса?
Фон:
- Согласно RFC 2616, § 9.5, POST используется для создания нового ресурса как подчиненного ресурсу, идентифицированному Request‑URI
- Согласно RFC 2616, § 9.6, PUT используется для создания или замены ресурса по указанному URI
Вопрос:
Какой метод HTTP следует использовать для создания ресурса, или оба должны поддерживаться в проектировании REST API?
Разница между методами HTTP POST и PUT проста, но критична для REST API: POST создает новый подчиненный ресурс по URI обработчика (сервер генерирует ID и возвращает Location), а PUT размещает или заменяет ресурс точно по указанному URI, оставаясь идемпотентным. Для создания ресурса без известного URI используйте POST — это стандарт по RFC 2616 (§9.5), а PUT подойдет, если клиент заранее знает путь, как рекомендует Roy Fielding. В дизайне REST API лучше поддерживать оба метода для гибкости: POST для коллекций, PUT для upsert-операций.
Содержание
- Что такое HTTP POST и когда его использовать
- Что такое HTTP PUT и его особенности
- Различия между POST и PUT по RFC 2616
- POST vs PUT для создания ресурсов в REST API
- Идемпотентность: почему это важно
- Рекомендации по дизайну REST API
- Источники
- Заключение
Что такое HTTP POST и когда его использовать
POST — это универсальный метод для отправки данных на сервер, но в контексте REST он идеален для создания новых ресурсов. Представьте: у вас есть эндпоинт /api/users — коллекция пользователей. Клиент шлет POST-запрос с JSON-телом { "name": "Иван", "email": "ivan@example.com" }. Сервер создает пользователя, присваивает ему уникальный ID (скажем, 123) и отвечает статусом 201 Created с заголовком Location: /api/users/123. Почему так? Потому что по RFC 2616 (§9.5) POST работает с подчиненным ресурсом: URI запроса — это обработчик (коллекция), а не точный путь будущего объекта.
Это удобно, когда клиент не знает ID заранее. Повторите запрос — и вуаля, дубликат. POST не идемпотентен, но это нормально для создания. А если сервер перегружен? Возвращает 429 Too Many Requests или 503. В реальности Postman подчеркивает: POST для новых сущностей, где сервер решает URI.
Пример curl:
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "Иван", "email": "ivan@example.com"}'
Ответ: HTTP/1.1 201 Created + Location.
Но подождите, а если нужно создать с предопределенным ID? Тут POST тоже сработает, но это не RESTful — лучше перейти к PUT.
Что такое HTTP PUT и его особенности
PUT — метод для точного размещения ресурса. Укажите полный URI, например /api/users/123, и сервер либо создаст ресурс там (если пусто), либо полностью заменит существующий. По RFC 2616 (§9.6) это атомарная операция: клиент знает URI заранее, шлет данные, и сервер обязан их сохранить именно туда. Идемпотентность на первом месте — повторите запрос 10 раз, результат один и тот же.
Статусы? 201 Created для нового, 200 OK или 204 No Content для замены, 409 Conflict если URI занят конфликтующим ресурсом. MDN для PUT уточняет: это не частичное обновление (для него PATCH), а полная замена.
Пример:
curl -X PUT https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Иван", "email": "ivan@example.com"}'
Если /users/123 не существовало — создано. Повторите — ничего не меняется. Идеально для миграций или когда клиент генерирует UUID заранее.
Но PUT требует знания URI. Если ID генерирует сервер — не ваш выбор.
Различия между POST и PUT по RFC 2616
RFC 2616 четко разграничивает: POST (§9.5) — для запросов, где URI это обработчик, результат может быть чем угодно (создание подчиненного ресурса, обработка формы). PUT (§9.6) — строго для ресурса по URI, с гарантией замены или создания.
Вот таблица сравнения из restfulapi.net:
| Аспект | POST | PUT |
|---|---|---|
| Семантика | Создание подчиненного ресурса | Создание/замена по точному URI |
| URI | Обработчик (e.g. /users) | Точный ресурс (e.g. /users/123) |
| Идемпотентность | Нет (дубли при повторe) | Да (повтор = тот же результат) |
| Статус при создании | 201 + Location | 201 Created или 200/204 |
| Тело | Любое | Полное представление ресурса |
Цитата из RFC для POST: “The request body is used to submit new data to the resource identified by the Request-URI”. Для PUT: “Replaces all current representations of the target resource”.
В KeyCDN добавляют: POST шире — для триггеров действий, PUT — чисто CRUD.
Разница не в “создать vs обновить”, а в контроле URI и безопасности повторных вызовов.
POST vs PUT для создания ресурсов в REST API
Для чистого создания ресурса? POST — ваш основной выбор. Почему? Клиент шлет на коллекцию /posts, сервер создает /posts/456 и возвращает ссылку. Это следует Fielding’у: в Stack Overflow он пишет, что PUT когда “клиент знает URI заранее”.
PUT для создания — редкость, но полезна: клиент генерирует ID (UUID), PUT /posts/abc-uuid-123. Если ресурс есть — upsert (update or insert). Baeldung приводит пример: в GitHub API PUT иногда upsert’ит.
А если оба? Поддерживайте! POST для “создай новый в коллекции”, PUT для “положи сюда”. REST Cookbook советует: коллекции — POST, известные пути — PUT.
Вопрос: а если клиент ошибся URI в PUT? 404 или 409. В POST — сервер спасет.
Идемпотентность: почему это важно
Идемпотентность — ключ. PUT: повторите 100 раз — один ресурс. POST: 100 дублей. Почему важно? Сети ненадежны. Таймаут? Клиент retransmit’нет. Для PUT — безопасно. POST — проверяйте сервером (e.g. unique email).
Пример из MDN POST: “Repeated identical POST may create multiple resources”. PUT нет.
В API добавляйте Idempotency-Key заголовок для POST, чтобы эмулировать. Но по умолчанию — PUT выигрывает в надежности.
Представьте заказ в e-commerce: POST /orders — новый заказ при сбое. PUT /orders/123 — безопасно обновит.
Рекомендации по дизайну REST API
В современном REST (RFC 7231 обновил 2616) оба метода обязательны. Стандарт:
- POST для создания без ID:
/api/items→ 201 Location. - PUT для создания/замены с ID:
/api/items/{id}→ 201/200/204. - Избегайте PUT без аутентификации — любой перезапишет.
- Всегда возвращайте Location в 201.
Software Engineering SE подтверждает: по Fielding, POST primary для создания. Но гибкость — король.
Тестируйте Postman: оба метода ускорят dev.
Источники
- What is the difference between POST and PUT in HTTP? — Объяснение различий от Roy Fielding и примеры: https://stackoverflow.com/questions/630453/what-is-the-difference-between-post-and-put-in-http
- PUT vs. POST: What’s the Difference? — Сравнение для создания ресурсов в API: https://blog.postman.com/put-vs-post/
- REST – Put vs Post — Детальный разбор по RFC 2616 с таблицами: https://restfulapi.net/rest-put-vs-post/
- PUT vs POST in REST API — Фокус на идемпотентности и статусах: https://www.baeldung.com/rest-http-put-vs-post
- PUT — Официальная документация MDN по PUT и статусам: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods/PUT
- POST — Официальная документация MDN по POST и семантике: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods/POST
- PUT vs POST — Рекомендации по URI и идемпотентности: https://www.keycdn.com/support/put-vs-post
- PUT vs POST — Практические советы по REST Cookbook: https://restcookbook.com/HTTP Methods/put-vs-post/
Заключение
Разница POST и PUT в REST API — в URI-контроле и идемпотентности: POST для новых ресурсов в коллекциях (сервер генерирует путь), PUT для точного размещения или замены. Используйте POST по умолчанию для создания, PUT когда ID известен — и обязательно поддерживайте оба для robust дизайна. Это сэкономит нервы при сетевых сбоях и сделает API по-настоящему RESTful.