Данная статья — перевод оригинального анонса Edge Rails: PATCH is the new primary HTTP method for updates.
Что такое PATCH?
HTTP-метод PUT предназначен для создания или замены ресурса по заданному URL. Возьмем, к примеру, файл. Когда вы загружаете файл в S3 по определенному URL, вы либо хотите создать его по тому адресу, либо заменить уже имеющийся там файл. Это PUT-запрос.
Далее представим веб-приложение, имеющее модель Invoice (счет), которая содержит флаг paid (оплачен?). Как установить значение этого флага в стиле RESTful? Установка paid=1 через PUT-запрос по адресу /invoices/:id не подойдет, т.к. такой запрос не обеспечит полной пересылки состояния счета.
С учетом ограничений методов GET, POST, PUT и DELETE, традиционным советом будет определить флаг оплаты в качестве отдельного ресурса. Тем самым вы определяете маршрут для установки paid=1 через PUT-запрос к /invoices/:id/paid. Вам придется поступить подобным образом, т.к. PUT не позволяет произвести лишь частичное обновление ресурса.
Давайте подумаем о самых обычных формах на обновление в типичном Rails-приложении. Как часто вы посылаете полное представление ресурса? Не всегда, быть может даже довольно редко в вашей практике. К примеру, временные метки created_at и updated_at обычно не управляются конечным пользователем, хотя зачастую они считаются принадлежащими ресурсу, который мапится на запись БД.
Ещё стоит учитывать, что PUT — идемпотентный метод. Вы должны быть готовы принять такой запрос сколь угодно много раз и каждый раз возвратить корректный ресурс. Такое нарушение привычной идиомы иногда случается, когда посредством вложенных атрибутов создаются дочерние ресурсы, приводящие к параллельному обновлению родительского.
Хотя теоретически ничто не препятствует применению PUT для пересылки частичных обновлений, но фактически семантика замены уже была учтена во время стандартизации HTTP. Метод PATCH был представлен в 1995 году, а позднее вошел в стандарты. PATCH — это метод, который не объявляется ни безопасным, ни идемпотентным, и позволяет производить полное или частичное обновление, возможно с побочным эффектом на смежные ресурсы.
На практике, как вы можете видеть, PATCH обычно в большей степени подходит для обновления ресурсов, чем PUT. В Ruby on Rails он естественным образом соотносится с методом update_attributes, который используется для обновления записей.
Тем самым, PATCH в Rails 4.0 выдвигается на первые роли.
Маршрутизация
Несмотря на серьезность изменений, мы планируем реализовать их так, чтобы сохранить обратную совместимость. Когда ресурс объявляется в routes.rb, например:
экшен на обновление в контроллере UsersController в Rails 4.0 будет по-прежнему называться update.
Запрос PUT по адресу /users/:id в Rails 4.0 будет, как и сегодня, маршрутизироваться к методу update. Т.о. если у вас есть API, которое производит вызовы PUT, оно по-прежнему будет работать.
Однако маршрутизация в Rails 4.0 также будет направлять на экшен update и PATCH-запросы к /users/:id. Т.е. и PUT и PATCH в Rails 4.0 будут маршрутизироваться к update.
Формы
Форма к сохраняемому ресурсу:
получит «patch» в скрытом поле "_method". Позволю себе заметить, что хак с "_method" — это просто способ обойти существующие ограничения браузеров. Как вы, вероятно, знаете, Rails вынуждена оперировать реальными методами HTTP, в т.ч. для обеспечения запросов PUT, DELETE, а теперь и PATCH.
Практическое применение
Запросы PATCH доступны во всех местах, где в текущий момент применимы остальные HTTP-методы. DSL маршрутизации подвергнется расширению, в частности хэш :via теперь будет понимать символ :patch. Тесты также смогут обрабатывать PATCH-запросы. Подробности см. в оригинальном коммите.
Будет ли моё приложение понимать PATCH?
Да. Я лично проверил Apache, nginx, Phusion Passenger, Unicorn, Thin и WEBrick: они все понимают запросы PATCH. HTTP-клиенты также должны в целом справляться с PATCH-запросами. Вы можете попробовать выполнить в curl такой запрос:
Что такое PATCH?
HTTP-метод PUT предназначен для создания или замены ресурса по заданному URL. Возьмем, к примеру, файл. Когда вы загружаете файл в S3 по определенному URL, вы либо хотите создать его по тому адресу, либо заменить уже имеющийся там файл. Это PUT-запрос.
Далее представим веб-приложение, имеющее модель Invoice (счет), которая содержит флаг paid (оплачен?). Как установить значение этого флага в стиле RESTful? Установка paid=1 через PUT-запрос по адресу /invoices/:id не подойдет, т.к. такой запрос не обеспечит полной пересылки состояния счета.
С учетом ограничений методов GET, POST, PUT и DELETE, традиционным советом будет определить флаг оплаты в качестве отдельного ресурса. Тем самым вы определяете маршрут для установки paid=1 через PUT-запрос к /invoices/:id/paid. Вам придется поступить подобным образом, т.к. PUT не позволяет произвести лишь частичное обновление ресурса.
Давайте подумаем о самых обычных формах на обновление в типичном Rails-приложении. Как часто вы посылаете полное представление ресурса? Не всегда, быть может даже довольно редко в вашей практике. К примеру, временные метки created_at и updated_at обычно не управляются конечным пользователем, хотя зачастую они считаются принадлежащими ресурсу, который мапится на запись БД.
Ещё стоит учитывать, что PUT — идемпотентный метод. Вы должны быть готовы принять такой запрос сколь угодно много раз и каждый раз возвратить корректный ресурс. Такое нарушение привычной идиомы иногда случается, когда посредством вложенных атрибутов создаются дочерние ресурсы, приводящие к параллельному обновлению родительского.
Хотя теоретически ничто не препятствует применению PUT для пересылки частичных обновлений, но фактически семантика замены уже была учтена во время стандартизации HTTP. Метод PATCH был представлен в 1995 году, а позднее вошел в стандарты. PATCH — это метод, который не объявляется ни безопасным, ни идемпотентным, и позволяет производить полное или частичное обновление, возможно с побочным эффектом на смежные ресурсы.
На практике, как вы можете видеть, PATCH обычно в большей степени подходит для обновления ресурсов, чем PUT. В Ruby on Rails он естественным образом соотносится с методом update_attributes, который используется для обновления записей.
Тем самым, PATCH в Rails 4.0 выдвигается на первые роли.
Маршрутизация
Несмотря на серьезность изменений, мы планируем реализовать их так, чтобы сохранить обратную совместимость. Когда ресурс объявляется в routes.rb, например:
resource :users
экшен на обновление в контроллере UsersController в Rails 4.0 будет по-прежнему называться update.
Запрос PUT по адресу /users/:id в Rails 4.0 будет, как и сегодня, маршрутизироваться к методу update. Т.о. если у вас есть API, которое производит вызовы PUT, оно по-прежнему будет работать.
Однако маршрутизация в Rails 4.0 также будет направлять на экшен update и PATCH-запросы к /users/:id. Т.е. и PUT и PATCH в Rails 4.0 будут маршрутизироваться к update.
Формы
Форма к сохраняемому ресурсу:
form_for @user
получит «patch» в скрытом поле "_method". Позволю себе заметить, что хак с "_method" — это просто способ обойти существующие ограничения браузеров. Как вы, вероятно, знаете, Rails вынуждена оперировать реальными методами HTTP, в т.ч. для обеспечения запросов PUT, DELETE, а теперь и PATCH.
Практическое применение
Запросы PATCH доступны во всех местах, где в текущий момент применимы остальные HTTP-методы. DSL маршрутизации подвергнется расширению, в частности хэш :via теперь будет понимать символ :patch. Тесты также смогут обрабатывать PATCH-запросы. Подробности см. в оригинальном коммите.
Будет ли моё приложение понимать PATCH?
Да. Я лично проверил Apache, nginx, Phusion Passenger, Unicorn, Thin и WEBrick: они все понимают запросы PATCH. HTTP-клиенты также должны в целом справляться с PATCH-запросами. Вы можете попробовать выполнить в curl такой запрос:
curl -d'user[name]=wadus' -X PATCH http://localhost:3000/users/1