В чем разница между методами HTTP POST и PUT, и когда каждый из них следует использовать для создания ресурса?
Фон:
- Согласно RFC 2616, § 9.5, POST используется для создания нового ресурса как подчиненного ресурсу, идентифицированному Request-URI
- Согласно RFC 2616, § 9.6, PUT используется для создания или замены ресурса по указанному URI
Вопрос:
Какой метод HTTP следует использовать для создания ресурса, или оба должны поддерживаться в проектировании REST API?
POST и PUT — это оба метода HTTP, используемые для манипуляции ресурсами в REST API, но они служат разным целям и имеют отличительные характеристики. POST создает ресурсы с URI, назначенными сервером, и является неидемпотентным, в то время как PUT создает или заменяет ресурсы в URI, указанных клиентом, и является идемпотентным. Выбор между ними зависит от того, знает ли клиент URI ресурса заранее, и нужна ли вам идемпотентность.
Содержание
- Ключевые различия между POST и PUT
- Когда использовать POST для создания ресурсов
- Когда использовать PUT для создания ресурсов
- Рассмотрения идемпотентности
- Лучшие практики проектирования REST API
- Альтернативные подходы
Ключевые различия между POST и PUT
Фундаментальные различия между методами POST и PUT вытекают из их спецификаций HTTP и предполагаемых случаев использования:
Метод POST:
- Определен в RFC 2616 §9.5 как “используется для создания нового ресурса как подчиненного ресурса, идентифицированного Request-URI”
- Сервер определяет URI нового созданного ресурса
- Обычно возвращает HTTP 201 (Created) с заголовком Location, указывающим на новый ресурс
- Неидемпотентен — повторные идентичные запросы могут создавать несколько ресурсов
- Используется для действий, не имеющих определенного сопоставления URI
Метод PUT:
- Определен в RFC 2616 §9.6 как “используется для создания или замены ресурса по указанному URI”
- Клиент указывает точный URI для ресурса, который создается или обновляется
- Обычно возвращает HTTP 200 (OK) или HTTP 204 (No Content) при успешных обновлениях
- Идемпотентен — повторные идентичные запросы имеют тот же эффект, что и один запрос
- Используется, когда клиент полностью знает идентификатор ресурса
Ключевое различие: POST создает ресурсы под контролем сервера, в то время как PUT создает или заменяет ресурсы в местоположениях, указанных клиентом. Это влияет как на процесс присвоения URI, так и на гарантии идемпотентности.
Когда использовать POST для создания ресурсов
POST является предпочтительным методом в следующих сценариях:
Создание дочерних ресурсов:
- При добавлении нового ресурса в коллекцию
- Пример: POST
/articlesсоздает новую статью в коллекции статей - Сервер назначает URI нового ресурса (например,
/articles/123)
Неизвестные URI ресурсов:
- Когда клиент не знает точный URI создаваемого ресурса
- Когда ресурсы имеют идентификаторы, сгенерированные сервером
- Когда ресурс подчинен другому ресурсу
Не-CRUD операции:
- Для действий, не вписывающихся в традиционные CRUD операции
- Для обработки форм или запуска операций
- Для пакетных операций или сложных рабочих процессов
Согласно лучшим практикам проектирования API от Microsoft, “POST-запросы используются для добавления нового ресурса в коллекцию, идентифицированную URI”. Это соответствует принципу RESTful, где POST работает с коллекциями, а не с конкретными ресурсами.
Пример: Создание новой учетной записи пользователя, где идентификатор пользователя генерируется автоматически сервером:
httpPOST /users Content-Type: application/json { "name": "John Doe", "email": "john@example.com" } HTTP/1.1 201 Created Location: /users/12345
Когда использовать PUT для создания ресурсов
PUT становится подходящим в следующих ситуациях:
URI ресурсов, указанные клиентом:
- Когда клиент знает точный URI создаваемого ресурса
- При использовании UUID или других идентификаторов, контролируемых клиентом
- При реализации оптимистичного контроля параллелизма
Идемпотентное создание ресурсов:
- Когда нужно гарантировать, что попытки дублирования создания не создают несколько ресурсов
- Когда один и тот же запрос можно безопасно повторить
- При реализации логики повторных попыток для надежных приложений
Полная замена ресурса:
- При создании или полной замене ресурса по конкретному URI
- При использовании PUT как для операций создания, так и обновления
Как объясняется на Baeldung, “используйте метод PUT для создания нового ресурса, а метод POST для обновления существующего ресурса” — это распространенный шаблон, хотя он может варьироваться в зависимости от решений по проектированию API.
Пример: Создание пользователя с UUID, указанным клиентом:
httpPUT /users/550e8400-e29b-41d4-a716-446655440000 Content-Type: application/json { "name": "John Doe", "email": "john@example.com" } HTTP/1.1 201 Created
Рассмотрения идемпотентности
Идемпотентность является ключевым фактором при выборе между POST и PUT:
Идемпотентность PUT:
- PUT является идемпотентным по спецификации HTTP
- Несколько идентичных запросов PUT дают тот же результат, что и один запрос
- Делает PUT безопасным для повторных попыток без побочных эффектов
- Критически важно для надежных распределенных систем
Неидемпотентность POST:
- POST по умолчанию не является идемпотентным
- Несколько идентичных запросов POST могут создавать несколько ресурсов
- Требует дополнительной серверной логики для предотвращения дублирования созданий
- Может потребовать пользовательских ключей идемпотентности или дедупликации запросов
Согласно RFC 7231, “метод запроса считается ‘идемпотентным’, если предполагаемый эффект на сервере от нескольких идентичных запросов с этим методом такой же, как эффект от одного такого запроса”. Методы GET, HEAD, PUT и DELETE обладают этим свойством.
Практические последствия:
- Сбои сети: PUT можно безопасно повторить; POST нельзя
- Повторные попытки клиента: PUT не вызовет дублирования ресурсов; POST может
- Контроль параллелизма: PUT хорошо работает с оптимистичной блокировкой
Лучшие практики проектирования REST API
При проектировании REST API учитывайте эти лучшие практики:
Последовательные шаблоны URI:
- POST
/resourcesдля создания ресурсов в коллекциях - PUT
/resources/{id}для создания или обновления конкретных ресурсов - Используйте четкие, иерархические структуры URI
Выбор кодов состояния:
- Успешное создание POST: HTTP 201 (Created)
- Создание/обновление PUT: HTTP 200 (OK) или HTTP 204 (No Content)
- Включайте заголовок Location для ресурсов, созданных через POST
Семантика методов:
- Следуйте принципам REST и семантике HTTP
- Используйте POST для действий, создающих ресурсы без указания URI
- Используйте PUT для операций, нацеленных на конкретные URI ресурсов
Лучшие практики проектирования API от Stack Overflow рекомендуют: “POST /articles/ предназначен для добавления новой статьи, PUT /articles/:id — для обновления статьи с заданным идентификатором.”
Рассмотрения со стороны клиента:
- Четко документируйте шаблоны URI для потребителей API
- Предоставляйте четкие сообщения об ошибках для недопустимых URI ресурсов
- Рассмотрите возможность поддержки обоих методов, когда это уместно
Альтернативные подходы
Хотя традиционные шаблоны хорошо установлены, некоторые современные API используют альтернативные подходы:
POST для создания и обновления:
- Некоторые API используют исключительно POST как для создания, так и для обновления
- Это упрощает проектирование API, но может строго не следовать принципам REST
- Распространено в архитектурах микросервисов
PUT только для создания:
- Некоторые API ограничивают PUT только созданием ресурсов
- Обновления обрабатываются через PATCH или другие методы
- Этот подход подчеркивает идемпотентность для создания ресурсов
Гибридные подходы:
- Используйте POST для неизвестных URI и PUT для известных URI
- Реализуйте пользовательские механизмы идемпотентности для POST-запросов
- Предоставляйте оба метода, когда случай использования поддерживает оба
Как отмечено в RESTful cookbook, “возможно, допустимо и даже предпочтительно в некоторых случаях использовать PUT для создания ресурсов или POST для обновления ресурсов.”
Заключение
Выбор между POST и PUT для создания ресурсов зависит от нескольких факторов:
- Контроль URI ресурса: Используйте POST, когда сервер назначает URI ресурса, и PUT, когда клиент его указывает
- Требования идемпотентности: Выбирайте PUT, когда вам нужна идемпотентность для безопасных повторных попыток
- Коллекции против отдельных ресурсов: Используйте POST для добавления в коллекции и PUT для нацеливания на конкретные ресурсы
- Последовательность API: Поддерживайте последовательные шаблоны во всем вашем проектировании API
На практике многие REST API поддерживают оба метода там, где это уместно — POST для общего создания ресурсов в коллекциях и PUT для создания ресурсов, когда клиент знает идентификатор. Это обеспечивает гибкость для разных случаев использования при сохранении принципов RESTful.
Для большинства приложений рекомендуется начинать с традиционного шаблона (POST для создания, PUT для обновлений), но будьте готовы адаптироваться в зависимости от ваших конкретных требований и потребностей потребителей вашего API.
Источники
- Stack Overflow - What is the difference between POST and PUT in HTTP?
- RESTful API - Difference between PUT and POST in REST API
- The Server Side - PUT vs POST: What’s the difference?
- Stack Overflow Blog - Best practices for REST API design
- Microsoft Learn - Web API Design Best Practices
- Baeldung - HTTP PUT vs. POST in REST API
- The RESTful Cookbook - When to use PUT or POST
- RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
- W3C - HTTP/1.1: Method Definitions
- MScharhag - HTTP methods: Idempotency and Safety