HATEOAS и формы, управляемые API
Я пытаюсь применить HATEOAS к существующему приложению, и у меня возникают проблемы с моделированием входных данных формы, которые будут управляться ответом API.
Приложение позволяет искать и бронировать связи между двумя местами. Первая конечная точка позволяет искать соединения GET /connections?from={lat,lon}&to={lat,lon}&departure={dateTime}
и возвращает следующую полезную нагрузку (тело ответа).
[
{
"id": "aaa",
"carrier": "Fast Bus",
"price": 3.20,
"departure": "2019-04-05T12:30"
},
{
"id": "bbb",
"carrier": "Airport Bus",
"price": 4.60,
"departure": "2019-04-05T13:30"
},
{
"id": "ccc",
"carrier": "Slow bus",
"price": 1.60,
"departure": "2019-04-05T11:30"
}
]
Чтобы сделать заказ на одно из подключений, клиент должен сделать POST /orders
запрос с одной из следующих полезных нагрузок (тело запроса):
- требуется электронная почта
{ "connectionId": "aaa", "email": "passenger@example.org" }
- адрес электронной почты и номер рейса (перевозчик обслуживает только aiprort-соединения)
{ "connectionId": "bbb", "email": "passenger@example.org", "flightNumber": "EA1234" }
- номер телефона требуется
{ "connectionId": "ccc", "phoneNumber": "+44 111 222 333" }
Полезная нагрузка различна, поскольку разные соединения могут обрабатывать разные соединения, и каждому из них может потребоваться предоставить какой-то разный набор информации. Я хотел бы сообщить клиенту API, какие поля обязательны при создании заказа. У меня вопрос, как мне это сделать с HATEOAS?
Я проверил различные спецификации, и это то, что я мог сказать, прочитав спецификации:
- HAL & HAL-FORMS Есть
"_templates"
но в самом шаблоне нет URI. Предполагается, что он работает с собственной связью, которая в моем случае была бы / соединения... не / заказы. - JSON-LD Я не смог найти ничего о поддержке форм или шаблонов.
- JSON-API Я не смог найти ничего о поддержке форм или шаблонов.
- Коллекция +JSON Существует не более одного
"template"
поэтому для каждого документа предполагается, что все элементы коллекции имеют одинаковые поля, что не так в моем приложении. - Сирена выглядит как
"actions"
подходит для моего варианта использования, но проект кажется мертвым, и нет никаких вспомогательных библиотек для многих основных языков. - CPHL Проект кажется мертвым, очень мало документации и нет библиотек.
- Ион Есть хорошая поддержка форм, но я не смог найти какие-либо вспомогательные библиотеки. Похоже, это просто спецификация на данный момент.
Является ли такая распространенная проблема, что формы, управляемые API, все еще не решены с помощью спецификаций и инструментов?
0 ответов
В вашем примере кажется, что Connections
ресурсы. Не совсем понятно, еслиOrders
действительно ресурсы. Думаю, наверное, да, но чтобыOrder
ты нуждаешься в Client
а также Connection
. Итак, чтобы создатьOrder
вам нужно будет открыть коллекцию, вероятно, из Client
или Connection
, возможно и то, и другое.
Я думаю, что отсоединение происходит от мысли, что "теперь, когда у нас есть список доступных подключений, клиент может выбрать одно и создать Order
."Это совершенно верно, но это мышление удаленного вызова процедур (RPC), а не REST. Ни один из них объективно не лучше другого, кроме как в контексте определенного набора требований проекта, и, как правило, их не следует смешивать.
С мышлением RPC определяется метод создания порядка (например, с использованием OpenAPI), и ожидается, что все клиенты будут использовать некоторую внеполосную информацию для определения требуемой правильной формы (например, путем чтения спецификации OpenAPI).
С мышлением REST/HATEOAS правильным подходом было бы раскрыть Orders
сбор из Connection
. КаждыйConnection
в коллекции есть self
ссылка и Order
s коллекция (ссылка или объект, как определено требованиями приложения). Каждый элементOrder
имеет self
ссылка, и именно там указаны возможности. AnOrder
- это известный тип (даже с REST/HATEOAS клиент и служба должны по крайней мере согласовать общий словарь), который клиент предположительно знает, как определить. Этот словарь можно определить с помощью любого работающего механизма - json-ld, XSD и т. Д.
HATEOAS требует, чтобы результат содержал все, что нужно клиенту для обновления состояния. Не может быть никакой внеполосной информации (кроме общего словаря). Итак, чтобы решить вашу проблему, вам нужно либо предоставить коллекциюOrder
с от Connection
или вам нужно разрешить Order
будет создан путем публикации в Connection
. Если последнее кажется чем-то вроде взлома, вероятно, так оно и есть.
Например, в HAL-Forms я бы сделал что-то вроде:
{
"connections": [{
"id": "aaa",
"carrier": "Fast Bus",
"price": 3.20,
"departure": "2019-04-05T12:30"
"_links": {
"self": { ... }, // link to this connection
"orders": {} // link to collection of orders for this connection
}
},
, ...],
"_links": {
"self": { ... } // link to the collection
},
"_templates": { ... } // post/put/patch/delete connection
}
Клиенты будут переходить по ссылкам на orders
и оттуда получит _templates
сборник, содержащий инструкции по управлению Order
Ресурсы. ВOrder
POST, скорее всего, потребует идентификатор соединения и информацию о клиенте. Спецификация HAL-Forms определяет свойство регулярного выражения, которое можно использовать для указания типа данных, предоставляемых для любого конкретного элемента формы. Поскольку вы достигли порядка, перейдя через определенное соединение, вы можете указать в своем_templates
для этого заказа, какие именно поля обязательны. например/orders?connectionType=aaa
вернет другой набор требуемых свойств, чем /orders?connectionType=bbb
но оба используют одно и то же self
ссылка /orders?connectionType={type}
и вы бы проверили его на POST/PUT/PATCH.
Я должен отметить, что Spring-HATEOAS выходит за рамки спецификации HAL-Forms и допускает несколько _links
а также _templates
. См. Эту проблему на GitHub.
Может показаться, что HATEOAS/REST требует немного больше работы, чем простой API OpenAPI/RPC, и это действительно так. Но от того, что вы отказываетесь от простоты, вы приобретаете гибкость и устойчивость, принимая хорошо спроектированных клиентов. Какой подход правильный, зависит от множества факторов, большинство из которых не являются техническими (навыки команды, ожидаемые потребители, степень вашего контроля над клиентами, обслуживание и т. Д.).