Подтвердить что ты не робот

Как следует внедрять ссылки типа HATEOAS для коллекций RESTful JSON?

Чтобы все было просто и чтобы избежать коллизий, я связывал ссылки в своих ресурсах записи, например...

{
    id: 211,
    first_name: 'John',
    last_name: 'Lock',
    _links: [
        { rel: 'self', href: 'htttp://example.com/people/211' }
    ]
}

Однако я не могу понять, как реализовать ссылки в коллекциях. Я потратил много времени на трафик в Интернете для примеров и других, кроме использования не очень скудного HAL. Я не могу смириться с моей проблемой.

[
    {id:1,first_name:.....},
    {id:2,first_name:.....},
    {id:3,first_name:.....}, 
    "_links": "Cant put a key value pair here because its an-array" 
]

Это означает, что я должен завершить массив в контейнере.

[
    people: [ {id:1,first_name:.....} ],
    links: [ { rel:parent, href:.... ]
]

Но это отличается от сингулярного ресурса, поэтому я собираюсь заставить запись вести себя как коллекция и обернуть ее в контейнере....

{
    person: {
        id: 211,
        first_name: 'John',
        last_name: 'Lock',
        _links: 
    },
    links:[
        { rel: 'self', href: 'htttp://example.com/people/211' }
    ] 
}

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

{
    "people": [
        {
            "person": {
                ....
            },
            "links" : [
                {
                    "rel": "self",
                    "href": "http://example.com/people/1"
                }
            ]
        },
        {
            "person": {
                ....
            },
            "links" : [
                {
                    "rel": "self",
                    "href": "http://example.com/people/2"
                }
            ]
        }
    ],
    "links" : [
        {
            "rel": "self",
            "href": "http://example.com/people"
        }
    ]
}

Есть ли более простое решение для реализации HATEOAS для коллекций? Или я должен поцеловать HATEOAS на прощание, заставив меня усложнить структуру данных?

4b9b3361

Ответ 1

Пожалуйста, не распускайте HAL так быстро, потому что он выглядит немного раздутым (в его форме JSON это довольно минимально).

HAL - это JSON, для чего HTML является простым текстом.

Он добавляет гиперссылки. Для REST вам нужны гиперссылки и общепринятый формат представления (например, HAL или Collection + JSON). Вам также нужен HATEOAS для REST, без HATEOAS это не ОТДЫХ! HATEOAS требует, конечно, гиперссылок.

В вашем случае вы пытаетесь создать ресурс коллекции. IANA-зарегистрированное отношение для этого является "item" (с обратной связью "collection" ). Вот представление в HAL для коллекции People:

{
    "_links": {
        "self": { "href": "http://example.com/people" },
        "item": [
            { "href": "http://example.com/people/1", "title": "John Smith" },
            { "href": "http://example.com/people/2", "title": "Jane Smith" }
        ]
    },
    "_embedded": {
        "http://example.com/rels#person": [
            {
                "first_name": "John",
                "last_name": "Smith",
                "_links": {
                    "self": { "href": "http://example.com/people/1" },
                    "http://example.com/rels#spouse": { "href": "http://example.com/people/2" }
                }
            },
            {
                "first_name": "Jane",
                "last_name": "Smith",
                "_links": {
                    "self": { "href": "http://example.com/people/2" },
                    "http://example.com/rels#spouse": { "href": "http://example.com/people/1" }
                }
            }
        ]
    }
}

Примечание:

  • Основные данные для этой коллекции взяты из _links.item[]. Это предметы в коллекции. Полные (или, по крайней мере, некоторые дополнительные) данные для каждого элемента доступны в массиве _embedded. Если клиенту нужны эти дополнительные данные, он должен найти их, выполнив поиск _embedded[n]._links.self.href для каждого n. Это конструктивное ограничение HAL. Другие форматы представления гипермедиа имеют сходные ограничения (хотя, возможно, и в другом направлении).

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

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

  • Все ваши гиперссылки должны быть абсолютными, поскольку относительные URL-адреса могут вызывать проблемы. Все ваши отношения должны быть либо указаны на этой странице IANA, либо использовать URI для их определения. В идеале, этот URI должен быть разыменованным URL-адресом HTTP с документацией относительно отношения на другом конце.

Ответ 3

Во-первых, я не верю, что API, у которого есть конечные точки, возвращающие коллекции (массивы JSON), действительно RESTful. Тем не менее, большинство API "REST" сгибают здесь правила.

Недавно я разработал API REST для NextBus XML-фида под названием restbus, который возвращает коллекции из некоторых конечных точек при использовании гипертекстовых ссылок типа HATEOAS. Вот пример структуры, которую я использовал:

{
  // ... SF-Muni resource from restbus API ...

  _links: {
    self: {
      href: "http://localhost:3535/agencies/sf-muni",
      type: "application/json",
      rel: "self",
      rt: "agency",
      title: "Transit agency 'sf-muni'."
    },
    to: [
      {
        href: "http://localhost:3535/agencies/sf-muni/routes",
        type: "application/json",
        rel: "describedby",
        rt: "route",
        title: "A collection of routes for transit agency 'sf-muni'."
      },
      {
        href: "http://localhost:3535/agencies/sf-muni/vehicles",
        type: "application/json",
        rel: "describedby",
        rt: "vehicle",
        title: "A collection of vehicles for transit agency 'sf-muni'."
      }
    ],
    from: [
      {
        href: "http://localhost:3535/agencies",
        type: "application/json",
        rel: "bookmark",
        rt: "agency",
        title: "A collection of transit agencies. This is the API root!"
      }
    ]
  }

}

Он не пытается следовать ни одной из популярных стратегий связывания JSON (или их связанных типов медиа), например HAL et al. потому что они, похоже, не находятся на IETF Standards Track (пока). Вместо этого значения и значения отношения ссылок соответствуют RFC 5988 Спецификации веб-ссылок как насколько это возможно.

Вы можете увидеть более подробную информацию о структуре гипертекстовой гиперссылки.

Ответ 4

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