RESTAPI: Каков правильный формат ответа и код состояния, если ресурс существует, но срок его действия истек? - PullRequest
1 голос
/ 15 апреля 2020

Предположим, у нас есть ресурс Employee. Сотрудник выглядит так (с точки зрения сущности и БД):

{
    id: 123,
    name: "John Doe",
    // more props here
    workPermitExpireDateUTC: "1999-06-30 00:00:00"
}

, когда мы запрашиваем всех сотрудников, мы хотим отобразить дополнительный флаг isExpired, рассчитанный на лету:

GET: /api/employees :

// HttpStatuCode: 200
[
    {
        id: 123,
        name: "John Doe",
        // more props here
        workPermitExpireDateUTC: "1999-06-30 00:00:00",
        workPermitExpired: true // calculated on a fly, based on system clock
    },
    {
        id: 456,
        name: "George Smith",
        // more props here
        workPermitExpireDateUTC: "2025-06-30 00:00:00",
        workPermitExpired: false // calculated on a fly, based on system clock
    }
]

Когда я запрашиваю одного не просроченного сотрудника

GET /api/employess/456 Я ожидаю получить 200 Response с данными сотрудника - это очевидно.

Однако, если мы рассматриваем сотрудника с истекшим сроком, я не хочу отправлять все данные, поскольку клиенту не нужно это знать. Поэтому я думаю вернуться так:

GET: /api/employees/123:

// HttpStatuCode: 200
{
    id: 123,
    workPermitExpired: true,
    errorMessage: "Employee work permit expired"
}

, но это не правильно, так как 200 ответ не должен иметь другую структуру в зависимости от идентификатора ресурса .

Как насчет такого URL GET: /api/employees/123/non-expired и возврата 200 в случае, если срок действия не истек, и 410 в случае истечения срока действия?

Ответы [ 2 ]

0 голосов
/ 15 апреля 2020

Что такое правильный формат ответа и код состояния, когда ресурс существует, но срок его действия истек?

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

Другой способ сказать то же самое: HTTP это приложение в домене для передачи документов по сети . Когда мы создаем API REST, мы делаем то, что адаптируем наши доменные протоколы к языку обмена документами с клиентом.

Коды состояния и заголовки принадлежат транспортным документам через сетевой домен.

GET: /api/employees/123

Правильный ответ на этот вопрос во многом зависит от того, имеется ли у нас текущее представление этого ресурса (что касается домена транспортных документов). Семантика 1017 * этого представления в нашем домене действительно не входит в него.

Если у нас есть текущее представление ресурса, то это штраф

200 OK
Content-Type: application/json

{
    "id": 123,
    "workPermitExpired": true,
    "errorMessage": "Employee work permit expired"
}

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

404 Not Found
Content-Type: application/json

{ "error": "Who is 123?" }

это не кажется правильным, так как ответ 200 не должен иметь различную структуру в зависимости от идентификатора ресурса.

Верно. Обычно это означает, что вы должны определить свою схему более тщательно. Если вы ожидаете включить или выключить некоторые поля в представлении, то в определении схемы необходимо описать эти поля как необязательные. Например, мы могли бы описать схему «активного разрешения» и схему «истекшего разрешения» (под другим ключом) с ограничением, что клиент должен ожидать одно или другое, но не оба.

Другая возможность использовать разные типы контента для разных представлений. RF C 6838 - это место, где вы ищите подробности, но в общих чертах мы можем определить две разные схемы, а затем присвоить каждой схеме отдельный тип контента

  • application / prs.maciej-active-allow + json
  • application / prs.maciej-expired-allow + json

application/+json сообщает потребителям общего назначения, что представления «просто» json документов, но потребители, знакомые с указанными вами c типами носителей, будут иметь более конкретное c понимание для работы.

RF C 7807 является стандартизированной демонстрацией этого подхода, где заданная c семантика для имен полей кодируется в json документе, а тип носителя application/problem+json сообщает компонентам общего назначения, что на самом деле происходит.

Вы видите похожую идею в application / merge-patch + json и application / json -patch + json.

0 голосов
/ 15 апреля 2020

Технически, у истекшего сотрудника нет того же типа ресурса, что и у сотрудника, например,

class ExpiredEmployee extends Employee

, поэтому 200 будет уместно, поскольку вы не возвращаете Employee. Вы возвращаете ExpiredEmployee.

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

GET /api/employess/456 для сотрудников с истекшим сроком действия

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

Если клиент не ожидает Сотрудник должен быть истек, возвращенный объект может запутать их. Возможно, отдельная конечная точка для бизнеса подойдет сотрудникам с истекшим сроком действия:

GET /api/employess/expired/456 для сотрудников с истекшим сроком действия

, поскольку, предположительно, любой, кто ищет 456, уже знает, что у него истек срок действия и хочет изменить своего сотрудника. статус?

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