Конечная точка REST: как правильно спроектировать действие на ресурсе?

63
6

У меня есть ресурс /contracts со следующей структурой:

{
name: "Contract name",
signedAt: 123213231,
// etc.
}

Хотя основные операции CRUD хорошо понятны (GET /contracts, GET /contracts/{id}, POST /contracts и т.д.), Некоторые сомнения возникают, когда я должен выполнить некоторые конкретные действия над ресурсом.

Одним из таких действий является следующее:

    знак: означает, что контракт подписан, поэтому дата signedAt должна быть обновлена с моментом (дата-время), который был подписан.

До сих пор я думал об этих разных подходах:

ПОВЫШЕНИЕ СРЕДЫ

Этот подход будет означать следующий метод конечной точки:

PATCH /contracts/{id}

и просто signedAt дату { signedAt: 123213231 } означающую, что после этого контракт будет подписан.

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

Полностью отбрасывается, так как дата signedAt должна быть установлена на стороне сервера точно в тот момент, когда знак будет выполнен.

Пополнение нового ресурса

Этот подход будет означать наличие действия подписи в качестве ресурса:

POST /contracts/{id}/sign

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

Пополнение ресурса с помощью "действия"

Подобно предыдущему подходу, в этом случае я бы использовал параметр запроса, называемый action на ресурсе контракта:

POST /contracts/{idContract}?action=sign

также с пустым телом, где ?action=sign. Как и в предыдущем подходе, когда-то размещенная бэкэнд-сторона была ответственна за инициализацию даты подписи.

Вопросы

    Каким будет подходящий способ, чтобы это было разработано на уровне API REST? Подходит ли какой-либо из подходов к хорошему дизайну или нет? Должен ли я изменить любой из подходов? Есть ли лучшая альтернатива?

спросил(а) 2021-01-25T18:20:28+03:00 5 месяцев назад
1
Решение
63

просто опубликовать подписанную дату {signedAt: 123213231}, означающую, что после этого контракт будет подписан.

По HTTP-патчу

Набор изменений представлен в формате, называемом "патч-документом", идентифицированным типом носителя.

Вместо того, чтобы перематывать свой собственный тип медиафайлов, вы можете подумать, подходит ли один из стандартных форматов.

Например: Патч JSON.

Content-Type: application/json-patch+json

[ { "op": "replace", "path": "signedAt", "value": 123213231 }

JSON Merge Patch - еще один разумный вариант

Content-Type: application/merge-patch+json

{ signedAt: 123213231 }

Из того, что я вижу, основное отличие заключается в том, что JSON Patch обеспечивает тестовую операцию, которая дает вам более тонкий контроль зерна, чем просто полагаться на валидаторы

Но вы абсолютно правы - PATCH дает полномочиям клиентского кода указывать значение времени. Если это не подходит для вашего случая использования, тогда PATCH является неправильным инструментом в поле.

POST /contracts/{id}/sign
POST /contracts/{idContract}?action=sign

Что касается REST/HTTP, эти два варианта эквивалентны - вы обновляете состояние одного ресурса, отправляя небезопасный запрос на другой ресурс. Есть несколько незначительных различий в том, как эти правописания действуют при разрешении ссылок, но в качестве целей запроса они не имеют никакого отношения к клиенту.

Вариант, который вы, кажется, упустили из виду:

POST /contracts/{id}

action=sign

Это имеет то преимущество, что при успешном завершении вы получаете бесплатное кэширование.

В API гипермедиа поток может выглядеть примерно так: клиент должен GET ресурс; потому что ресурс еще не подписан, представление может содержать форму с кнопкой "знак" на ней. Действие в форме будет /contracts/{id}. Потребитель "подписывает" договор, отправив форму - агент собирает информацию, описанную в форме, кодирует ее в тело запроса и затем отправляет запрос на сервер. Сервер отвечает за успех, а кеш клиента знает, чтобы аннулировать ранее выбранную копию ресурса.

ответил(а) 2021-01-25T18:20:28+03:00 5 месяцев назад
45

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

    Создайте собственный конвертер для значений даты в службе отдыха, который принимает дату и другие определенные поля. Если вы проверяете API отчетов Google, например, они позволяют использовать определенный диапазон дат, а также CURRENT_WEEK, CURRENT_MONTH и т.д. Таким образом, вы можете добавить такое конкретное значение и использовать его. Например, PATCH signedAt = CURRENT_DATE и API обрабатывает это правильно.

    Добавьте в ресурс логическое поле. Сделайте POST или PATCH со знаком = true. Таким образом, вы сможете в конечном итоге легко запросить только подписанные ресурсы;) Также может быть, что люди заботятся только о том, подписано ли это, чем когда оно было подписано


Я бы не использовал? Action = sign или /contract/{id}/sign, потому что они не являются RESTFUL, и даже если вы используете GET и POST, вы будете использовать их таким образом, чтобы создать обходной путь для реализации действий в вашем дизайн, который не должен иметь действий

ответил(а) 2021-01-25T18:20:28+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема