RESTful имя метода, выполняющего две операции

В API у меня есть ресурс билетов и есть 2 метода:

1) Получить статус тикета (билет можно заблокировать/разблокировать)

GET /api/tickets/:id

2) Обновить статус тикета

PUT /api/tickets/:id with status=locked|unlocked

Что мне нужно, так это совместить проверку статуса с фактическим обновлением в одном вызове API. И мне также нужно знать, изменился ли статус при вызове API или он уже был установлен на нужное значение. Например:

ticket_status = "unlocked"
PUT /api/tickets/:id/check_lock
changes ticket_status to "locked" and responses with "success"

ticket_status = "locked"
PUT /api/tickets/:id/check_lock
ticket_status is already "locked" so we response with "ignored"

Для обратной операции мы можем иметь

PUT /api/tickets/:id/check_unlock

Я понимаю, что здесь мы нарушаем принцип единой ответственности, объединяя операции, но это делается для уменьшения количества запросов API, и это будет вызываться очень часто.

Поэтому я ищу хорошие имена вместо этих уродливых «check_lock», «check_unlock», поскольку они кажутся довольно двусмысленными.


person sybrex    schedule 15.05.2017    source источник
comment
Зачем нужна проверка статуса, если заблокировать уже заблокированный тикет или разблокировать разблокированный вроде бы не представляет никакой проблемы? Идемпотентность — отличный способ просто не заботиться об этом.   -  person guillaume31    schedule 15.05.2017
comment
Это упрощенный пример. У меня есть очередь билетов для обработки. Если билет заблокирован, мне нужно отложить его обработку и поместить в хвост очереди. Так что мне нужно знать, был ли он заблокирован или нет.   -  person sybrex    schedule 15.05.2017
comment
Если тикет заблокирован, вы все равно обновляете ресурс (успешно ли выполняется PUT) или операция прерывается?   -  person guillaume31    schedule 15.05.2017
comment
Когда тикет разблокирован, мы обновляем его и возвращаем ответ с модифицированным=true. Если тикет заблокирован, мы не вносим никаких изменений и возвращаем ответ с модифицированным=false. Решил следовать подходу с POST /api/tickets/:id/toggle_lock, рекомендованному andih.   -  person sybrex    schedule 15.05.2017


Ответы (3)


Используя что-то вроде

PUT /api/tickets/:id/check_lock

обновлять статус блокировки не рекомендуется (как бы не сказать плохая практика). При чтении check_something обычно думают о безопасном методе, т. е. не ожидают изменения какого-либо значения.

Ваш пример PUT не является идемпотентным. то есть вызов PUT два раза для одного и того же ресурса приводит к разным результатам. Что противоречит HTTP-спецификации для PUT.

Запрос PUT определяется как замена состояния целевого ресурса.

В вашем случае лучше всего использовать PATCH для обновления ресурса билета части, как описано в RFC5789 или даже https://tools.ietf.org/html/rfc6902

PATCH /api/tickets/:id/ HTTP/1.1
Host: example.org
Content-Type: application/json-patch+json

{ "op": "replace", "path": "/lock", "value": "unlock"  }

Вы можете выбрать ETag в своем ответе, чтобы сообщить, был ли изменен ресурс или нет.

Или просто код состояния HTTP 200 с телом сообщения, в котором вы возвращаете, был ли ресурс изменен или нет, а также новое значение состояния блокировки.

Если вы хотите переключить статус блокировки, вы должны использовать что-то вроде «ресурса действия». В этом случае используйте POST.

POST /api/tickets/:id/toggle_lock

В результате вы можете вернуть новый статус блокировки и узнать, был ли он обновлен или нет, как часть тела кода состояния HTTP 200.

person andih    schedule 15.05.2017

Подумав в ресурсах, у меня не было бы операции check_unlock. Я бы предложил: ПОЛУЧИТЬ /api/tickets/:id со статусом билета в ответе json. Даже если у вас есть два http-вызова.

Или если статус выдает ошибку, можно ответить ошибкой 400 или что-то в этом роде.

person Torsten    schedule 15.05.2017

Я бы использовал немного другой подход и использовал код состояния 409 Conflict.

Запрос не может быть выполнен из-за конфликта с текущим состоянием ресурса. Этот код разрешен только в тех случаях, когда ожидается, что пользователь сможет разрешить конфликт и повторно отправить запрос.

Успешная сессия:

PUT /api/tickets/123 { ... locked: true ... }
200 OK

Уже заблокированная сессия:

PUT /api/tickets/123 { ... locked: true ... }
409 Conflict
POST /api/ticket-queue { // ticket data here }
201 Created
person guillaume31    schedule 16.05.2017