Restful Service и Generic Media Type Payload and stay HATEOAS

Простите меня, поскольку я все еще новичок в этом RESTFUL, я читал блоги и т. д., и у всех у них действительно разные реализации/рекомендации, единственной реальной рекомендацией является Модель зрелости Ричардсона, которая определяет, что такое Hypermedia.

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

Я пытаюсь разработать веб-сервис RESTFUL API, и я планирую использовать GENERIC MEDIA TYPE, например, HAL или Collection + Json или Siren и т. д. Или, возможно, создать свой собственный тип носителя, который я не думаю, что хочу вдаваться сейчас...

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

1) Нужно ли где-то указывать определение структуры данных? или шаблон формы какой-то? Я видел несколько примеров, когда они помещали свое определение этих данных в удобочитаемый формат, например, «someurl/doc? Или мы должны использовать что-то вроде схемы json?

2) Некоторые примеры, которые я видел, украшали свои элементы данных типом ссылки из vcard/foaf и т. д., например. "name": "http://xmlns.com/foaf/0.1/name". Что это значит? В некоторых примерах, которые я вижу, есть ссылки на их имя someurl/doc# для описания объекта имени и т. д.

3) Означает ли это, что при изменении полезной нагрузки модели приложения меняется интерпретатор контракта? И поэтому все клиенты ломаются по-прежнему, как в SOAP?

4) Еще одна альтернатива, я думаю, что у меня может быть эволюционируемая структура элемента, такая как объект элемента collection + json с именем, значением, подсказкой, которая формирует фактическую структуру, таким образом, будут минимальные изменения контракта на стороне клиента. потребляя его.

Пожалуйста, посоветуйте, как мне спроектировать свой объект, в основном скажем, что у меня есть ОБЪЕКТ ПРИЛОЖЕНИЯ с несколькими ЗАЯВИТЕЛЯМИ с НЕСКОЛЬКИМИ АДРЕСАМИ, чтобы упростить вопрос.

Джош


person Joshscorp    schedule 12.06.2013    source источник


Ответы (1)


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

  1. Зависит от вашей аудитории. Используйте то, что им будет проще всего потреблять. Являются ли они универсальными автоматическими агентами, которые могут понимать схему, или они являются разработчиками, работающими специально для вашего API. В любом случае вам всегда будут нужны удобочитаемые документы, поэтому я бы начал с этого. Если вы решите принять application/x-www-form-urlencoded тело запроса, то HTML-форма будет отличным способом предоставления рабочего шаблона.
  2. Это определяет «тип» поля. Итак, name is a foaf:name говорит вам, что поле с именем name содержит значение типа http://xmlns.com/foaf/0.1/name. Вы должны прочитать о RDF, формате описания ресурсов, и посмотреть на представления, такие как Turtle и N3, которые должны прояснить это. Концепция отношений, которые являются URI (вместо простых строк), исходит оттуда, хотя отношения ссылок — это не то же самое, что свойства RDF, такие как owl:sameAs или foaf:name. Оба представлены ребрами в ориентированном графе.
  3. Пожалуйста, объясните подробнее, вы имеете в виду добавленные/удаленные поля или совершенно другой тип контента? Я бы сказал, что последний является другим ресурсом и должен иметь другой URI. Ваши клиенты должны будут либо понимать, либо иметь возможность игнорировать любые будущие изменения, которые вы вносите в свои ресурсы.
  4. Все предложенные вами типы контента должны развиваться таким образом. Это именно предпосылка HATEOAS.

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

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

Пример реализации с использованием HAL:

Запрос:

GET / HTTP/1.1
Host: example.com
Accept: application/hal+json

Ответ:

HTTP/1.1 200 OK

{ "_links": {
    "self": { "href": "/" },
    "http://example.com/docs/applicant": [
      { "href": "/applicant1" },
      { "href": "/applicant2" },
      { "href": "/applicant3" }]
} }

Затем клиент будет искать гиперссылки, которые имеют отношение http://example.com/docs/applicant, которое является просто строкой и может быть fishmonkeygiraffe, если вы хотите. Преобразование строки в URL-адрес http позволяет разработчикам клиента легче находить вашу документацию, а также связывать области видимости с помощью префикса это с уникальной строкой: ваш собственный домен. Формат ответа может быть любым форматом с поддержкой гипертекста, например HTML, при условии, что клиент знает, как найти внутри него гиперссылки (элементы ‹LINK> и ‹A>), или вы можете вернуть их в заголовке HTTP Link, но тогда клиент несет ответственность за их хранение, если ему нужно записать извлеченный ресурс на диск.

Затем клиент запрашивает тот, на который он хочет посмотреть:

GET /applicant1 HTTP/1.1
Host: example.com
Accept: application/hal+json

Ответ:

HTTP/1.1 200 OK

{ "_links": {
    "self": { "href": "/applicant1" },
    "http://example.com/docs/applicant-address": [
      { "href": "/applicant1/address1" },
      { "href": "/applicant1/address2" },
      { "href": "/applicant1/address3" }]
} }

Очевидно, что «заявитель1» может быть чем угодно, например. "претенденты/1" или "вакансии/sweet-менеджер/кандидаты/дэйв-смит". Клиент просто переходит по указанному URL-адресу.

Затем клиент выбирает гиперссылку типа http://example.com/docs/applicant-address для получения:

GET /applicant1/address1 HTTP/1.1
Host: example.com
Accept: application/hal+json

Ответ:

HTTP/1.1 200 OK

{ "_links": {
    "self": { "href": "/applicant1/address1" },
    "edit-form": { "href": "/applicant1/address1/edit" },
    "http://example.com/docs/applicant": { "href": "/applicant1" }
  },

  "street": "5 Dungeon Drive",
  "town": "Snotty Hill",
  "county": "London",
  "postcode": "NE5 2LT",
  "country": "GB",
}

Теперь клиент хочет изменить адрес, поэтому он переходит по гиперссылке с отношением «форма редактирования»: (см. отношения связи IANA)

GET /applicant1/address1/edit HTTP/1.1
Host: example.com
Accept: text/html

Ответ:

HTTP/1.1 200 OK

<!DOCTYPE HTML>
<form action="/applicant1/address1" method="POST">
  <input name="street" value="5 Dungeon Drive">
  et cetera
</form>

В результате чего:

POST /applicant1/address1 HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

street=5%20Dungeon%20Drive&...

Я использовал HAL, потому что HAL похож на JSON-версию XML + XLink, просто его проще вводить в примерах SO;), то есть это общий формат синтаксического анализа с поддержкой гипермедиа, не более того. Все взаимодействие управляется связными отношениями. Веб-браузеры знают, что делать со ссылкой rel="stylesheet", потому что они знают, что означает это отношение. Приведенный выше список отношений ссылок, определенный IANA, — это те, которые вы должны выбрать в первую очередь (очень полезны item и collection), а затем, если то, что вы ищете, недостаточно конкретно, попробуйте найти общедоступный список отношений ссылок, относящихся к вашего сектора (например, посмотрите, какие API публикует лидер рынка) и повторно используйте их, если это возможно. Это позволит инструментам стать интероперабельными, поскольку все они ищут одни и те же отношения ссылок. Ваш пример Dublin Core в вопросе представляет собой аналогичный репозиторий публично определенных свойств RDF.

Для гиперссылок связь (контракт) заключается не между клиентом и вашим сайтом, а между клиентом и набором отношений. Отношения должны быть как можно более известными (это то, что имеет в виду Википедия, когда говорит «общее понимание гипермедиа»).
Для полей ресурсов, если вы хотите, чтобы ваш ресурс Решение на основе RDF, использующее известные свойства RDF, которые тесно связаны с вашей сферой бизнеса. Существует несколько сериализаций RDF в JSON, но на данный момент нет явного лидера. На данный момент вам, вероятно, будет лучше поддерживать только XML. Сообщение в блоге Шесть простых шагов из JSON в RDF могут оказаться полезными для изучения основ RDF.

person Nicholas Shanks    schedule 12.06.2013
comment
3) Например, если у вас есть модель/DTO, которая имеет 3 поля, идентификатор, имя, описание, например, в полезной нагрузке ранее. Теперь вы хотите изменить его на id, другое имя, другое описание, не сломается ли клиентский код? Как и в SOAP, когда WSDL Changes, также известный как контракт, изменился, вам не придется переделывать код на стороне клиента? - person Joshscorp; 12.06.2013
comment
Можете ли вы привести пример простой полезной нагрузки, о которой вы говорите? Скажем, приложение в качестве верхнего уровня с именем, датой отправки, описанием, типом, полями, нужен ли им всем RDF, о котором вы говорили в 2)? - person Joshscorp; 12.06.2013
comment
если вы ИЗМЕНИТЕ имя на другое имя, тогда да, поиск имени сломается. Но это верно для любого формата и любой архитектуры реализации. Вам нужно будет отправить как старую этикетку, так и новую. Я добавлю пример к ответу. - person Nicholas Shanks; 12.06.2013
comment
Спасибо за отличный пример... но, на мой взгляд, он все еще очень связан... в википедии... определение HATEOAS определяется как клиент REST, которому не нужны предварительные знания о том, как взаимодействовать с каким-либо конкретным приложением или сервером за пределами общее понимание гипермедиа. Сравните это, например. сервис-ориентированная архитектура (SOA), в которой клиенты и серверы взаимодействуют через фиксированный интерфейс, совместно используемый через документацию или язык описания интерфейса (IDL). Итак, изменение имени на другое имя = изменение интерфейса для меня, иначе HATEOAS? - person Joshscorp; 13.06.2013
comment
Насколько я понимаю до сих пор, HAL, который является общим типом носителя, должен быть задокументирован и понят клиентом, после внедрения он должен иметь возможность свободно развиваться без изменения клиентской стороны, включая полезную нагрузку, что меня очень смущает даже в вашем примере вам нужны специальные знания о формате полезной нагрузки, интерфейсе, IDL, документации и т. д., что для меня противоположно определению HATEOAS? В вашем примере клиент сломается, если вы переименовали улицу в полезной нагрузке адреса на что-то другое. - person Joshscorp; 13.06.2013
comment
@Joshscorp HAL довольно уникален тем, что для понимания полезной нагрузки встроенных представлений вы используете спецификацию отношения ссылок, с которой связан встроенный ресурс. Следовательно, клиенту не нужно документировать конкретный экземпляр представления HAL, но ему необходимо документировать отношения ссылок, в которых конкретно указывается, какие свойства потенциально могут быть внедрены. - person Darrel Miller; 13.06.2013
comment
@Joshscorp Если вы измените встроенную полезную нагрузку, чтобы использовать other-name вместо «имени», вам нужно будет создать новое отношение ссылки, чтобы клиент знал, что что-то изменилось. REST не устраняет связь, он просто фокусирует связь на типах медиа и связях. Это упрощает управление муфтой. И поскольку отношения ссылок и типы мультимедиа всегда включены в представление, клиент ВСЕГДА знает, понимает ли он информацию или нет. Не может быть критических изменений без того, чтобы клиент узнал об этом. - person Darrel Miller; 13.06.2013
comment
REST не устраняет связь, он просто фокусирует связь на типах медиа и связях. <- Да! Что сказал Даррел. Он тут спец :) - person Nicholas Shanks; 13.06.2013
comment
Это отличный ответ, однако лично я бы смягчил отказ от создания новых типов медиа. Я бы предпочел видеть слишком много чрезмерно специфичных типов мультимедиа, чем людей, туннелирующих семантику через общие типы мультимедиа. Есть баланс, но я считаю, что есть много возможностей для создания действительно полезных многоразовых типов носителей, которыми мы не пользуемся. - person Darrel Miller; 13.06.2013
comment
@DarrelMiller Возможно. Мой жизненный опыт в целом подводит меня к позиции, согласно которой конкретизация, основанная на часто используемых общих шаблонах (т. е. философия, напоминающая коровью тропу), оказалась более успешной, чем попытки пойти другим путем (построй его, и они придут, башня из слоновой кости). Спецификации внедряются в секторы рынка.) Последнее часто работает только в том случае, если есть поставщик-гигант, продвигающий свой собственный синтаксис. - person Nicholas Shanks; 13.06.2013
comment
давайте продолжим это обсуждение в чате - person Darrel Miller; 13.06.2013