Что сделать, когда Вам нужно больше глаголов в REST

Существует другой подобный вопрос взорвать, но обсуждение повернуло далеко от проблемы, я - encounting.

Скажите, что у меня есть система, которая имеет дело с отчетами о расходах (ER). Можно создать и отредактировать их, прикрепить вложения и одобрить/отклонить их.

Отчет о расходах мог бы быть похожим на это:

GET /er/1
=>
{"title": "Trip to NY", "totalcost": "400 USD",
 "comments": [
   "john: Please add the total cost",
   "mike: done, can you approve it now?"
   ],
 "approvals": [
   {"john": "Pending"}, {"finance-group": "Pending"}]
}

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

Если Вы хотите обновить его, можно сделать это:

POST /er/1
{"title": "Trip to NY 2010"}

Если Вы хотите утвердить его, можно сделать это:

POST /er/1/approval
{"approved": true}

Но, что, если Вы хотите обновить отчет и утвердить его одновременно? Как мы делаем это? Если Вы только хотели одобрить, то выполнение a POST к чему-то как /er/1/approval имеет смысл.

Мы могли поместить флаг в URL, POST /er/1?approve=1, и отправьте изменения данных как тело, но тот флаг не кажется УСПОКОИТЕЛЬНЫМ.

Мы могли поместить специальное поле, которое будет отправлено также, но это кажется небольшим hacky, также. Если мы сделали это, то почему бы не повысить данные с атрибутами как set_title или add_to_cost?

Мы могли создать новый ресурс для обновления и одобрения, но (1) я не могу думать, как назвать его без глаголов и (2) это не кажется правильным для именования ресурса на основе того, какие действия могут быть сделаны к нему (что происходит, если мы добавляем больше действий?)

У нас мог быть X-Approve: заголовок True|False, но заголовки походит на неправильный инструмент для задания. Также было бы трудно получить установленные заголовки, не используя JavaScript в браузере.

Мы могли использовать пользовательский тип среды, application/approve+yes, но это кажется не лучше, чем создание нового ресурса.

Мы могли создать временный URL "пакетных обработок", /er/1/batch/A. Клиент затем отправляет несколько запросов, возможно POST /er/1/batch/A обновить, затем POST /er/1/batch/A/approval одобрить, затем POST /er/1/batch/A/status закончить пакет. На бэкенде сервер стоит в очереди все пакетные запросы где-нибудь, затем обрабатывает их в той же транзакции бэкенда, когда это получает "запрос" пакетной обработки конца. Оборотная сторона с этим, очевидно, что она представляет большую сложность.

Так, что такое хороший, общий способ решить проблему выполнения нескольких действий в единственном запросе? Общий, потому что его легкое для воображения дополнительных действий, которые могли бы быть сделаны в том же запросе:

  1. Подавите или отправьте уведомления (в электронную почту, чат, другую систему, безотносительно)
  2. Переопределите некоторую проверку (максимальная стоимость, имена посетителей ужина)
  3. Триггерный рабочий процесс бэкенда, который не имеет представления в документе.

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

27
задан Community 23 May 2017 в 11:46
поделиться

3 ответа

Архитектура REST утверждает, что ресурс управляется сервером и идентифицируется по URL-адресу.

В этом свете / er / 1 / подтверждение не является разумным URL-адресом или моделью для использования, если у вас нет объекта утверждения или сущности, которой вы управляете и которыми манипулируете на стороне сервера. Мне кажется, что сущность - это сам отчет о расходах, что означает, что / er / 1 - это ваш URL-путь.

Теперь, что касается глаголов ... вы можете отправить (POST) любое сообщение на этот ресурс.

установить данные:

{ action: "modify", data: { purpose : "Club hopping" } }

утвердить:

{ action: "approve" }

добавить элемент:

{ action:"additem", data: { amount:72.13, category:113, note:"client dinner" }}

и т. Д.


Из Ch5 Филдинга, который определяет REST ,

Входные параметры (запроса) состоят из данных управления запросом, идентификатора ресурса, указывающего цель запроса, и необязательного представления.

... и ...

Управляющие данные определяют цель сообщения между компонентами , например, запрашиваемое действие или значение ответа. Он также используется для параметризации запросов и переопределения поведения по умолчанию некоторых соединительных элементов. Например, поведение кэша может быть изменено управляющими данными, включенными в сообщение запроса или ответа.


Поэтому, если вы хотите выполнить несколько действий с ресурсом, вам следует встроить в «управляющие данные» несколько сообщений или запросов действий. В моем примере опубликованные данные будут выглядеть примерно так:

{ action: "modify", data: { purpose : "Club hopping" } }
{ action: "approve" }

Но вы, вероятно, захотите обобщить это так, чтобы это было:

{ actions: [ {action:"modify", data: {...} }, { action:"approve"} ] } 

Сообщения или действия, которые ваш сервер может обрабатывать для каждого конкретного типа объекта, зависит от вас. определить.

ps: иногда реализации REST используют HTTP PUT для создания ресурса и POST для изменения существующего ресурса или действий с ним.

и: Мне понравилась статья Как ПОЛУЧИТЬ чашку кофе .

24
ответ дан 28 November 2019 в 05:41
поделиться

Для управления статусом ресурсов я часто использую «сегменты статуса». Идея состоит в том, что когда вы «добавляете» объект в эту корзину, он получает этот статус. Это похоже на то, что у вас на столе лежат ящики с входящими и выходящими товарами. Местоположение документа определяет его статус.

Итак, вы можете сделать что-нибудь простое, например:

POST /Expenses/Approved
{ .. Expense document ... }

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

POST /ExpenseApprover/John/ApprovedExpenses
{ .. Expense document ... }

Если вам нужно отправить отчет о расходах на утверждение, вы можете сделать это

POST /ExpenseApprover/John/Pending
{ .. Expense document ... }

И не забывайте, что гипермедиа может включить этот рабочий процесс. Представьте, что кто-то создает отчет о начальных расходах, сервер может ответить следующим JSON.

{ "id" : "234",
  "title": "Trip to NY", "totalcost": "400 USD",
  "submit_url": "/ExpenseApprover/John/Pending"
}

Клиент может выполнить POST на submit_url, чтобы переместить расходы на следующий шаг. Затем, когда Джон извлекает расходы, он получает

{ "id" : "234",
  "title": "Trip to NY", "totalcost": "400 USD",
  "approve_url": "/ExpenseApprover/Finance/Pending",
  "denied_url": "/ExpenseApprover/John/Denied",
}

Когда финансовый отдел выполняет

GET /ExpenseApprover/Finance/Pending

, они могут получить список ожидающих расходов,

{ PendingExpense: [
    { "id" : "234",
      "title": "Trip to NY", "totalcost": "400 USD",
     "approve_url": "/Expense/Approved",
     "denied_url": "/ExpenseApprover/Finance/Denied",
    }
   ]
}

Простите мой ужасный JSON, но я надеюсь, что вы уловили идею, что включение ссылки в ответ вы можете направить поток вашего приложения. Вы также можете перестать так сильно беспокоиться о том, как выглядит URL-адрес, потому что клиенту все равно. Клиент считывает URL-адрес из ответа на основе имени свойства и разыменовывает его. Вы можете миллион раз передумать о том, какая структура URL-адресов лучше, и это не повлияет на ваших клиентов. Только не меняйте название свойства!

Эти URL-адреса «корзины состояния» используются для хранения набора ресурсов с аналогичным статусом.Идея состоит в том, что вы POST документ в коллекцию:

POST /ExpenseApprover/Finance/Denied

{"id" : "234", "title": "Trip to NY", "totalcost": "400 USD"}

Нет необходимости однозначно определять конкретные расходы, которые вы добавляете в URL-адрес, потому что основной документ должен содержать какое-то значение идентифицирующего ключа.
Этот метод также применим для отметки расходов, имеющих неточности. Вы просто создаете новый ресурс, который содержит расходы с несоответствиями, и публикуете в нем отчет о расходах.

POST /Discrepancies
{"id" : "234", "title": "Trip to NY", "totalcost": "400 USD"}
4
ответ дан 28 November 2019 в 05:41
поделиться

Я думаю, вы усложняете задачу, чем она должна быть. Относитесь к отчету о расходах как к полному ресурсу, и любые изменения в нем - это просто ПОСТАВЛЕНИЕ нового представления в URI, в котором находится ресурс. Не нужно настраивать действия для изменения статуса, просто ПОЛУЧИТЕ ресурс - внесите изменения - затем верните его обратно. Выполнено.

1
ответ дан 28 November 2019 в 05:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: