Я пришел к выводу, что создание действительно RESTful API, использующего HATEOAS, практически невозможно.
Каждый контент, с которым я сталкивался, не иллюстрирует истинную силу HATEOAS. или просто явно не упоминает болевые точки, присущие динамической природе HATEOAS.
Насколько я понимаю, настоящий HATEOAS API должен иметь ВСЮ информацию, необходимую для взаимодействия с API, и хотя это возможно, использовать его — кошмар, особенно с разными стеками.
Например, рассмотрим коллекцию ресурсов, расположенную в «/books»:
{
"items": [
{
"self": "/book/sdgr345",
"id": "sdgr345",
"name": "Building a RESTful API - The unspoken truth",
"author": "Elad Chen ;)",
"published": 1607606637049000
}
],
// This describes every field needed to create a new book
// just like HyperText Markup Language (i.e. HTML) rendered on the server does with forms
"create-form": {
"href": "/books",
"method": "POST",
"rel": ["create-form"],
"accept": ["application/x-www-form-urlencoded"],
"fields": [
{ "name": "name", "label": "Name", "type": "text", "max-length": "255", "required": true }
{ "name": "author", "label": "Author", "type": "text", "max-length": "255", "required": true }
{ "name": "author", "label": "Publish Date", "type": "date", "format": "dd/mm/YY", "required": true }
]
}
}
Давая приведенный выше ответ, клиент (например, веб-приложение) может использовать свойство «create-form» для отображения фактической HTML-формы.
Какую ценность мы получаем от всей этой работы?
То же самое значение, которое мы получаем от HTML в течение многих лет.
Подумайте об этом, это именно то, что представляет собой гипертекст и для чего HTML был разработан.
Когда браузер нажимает на «www.pizza.com», браузер не знает о других путях, которые пользователь
можно посетить, он не объединяет строки для создания ссылки на страницу заказа -> «www.pizza.com/order», он просто отображает якоря
и перемещается, когда пользователь нажимает на них. Именно это позволяет веб-разработчикам изменять путь с «/order» на «/shut-up-and-take-my-money» без изменения какого-либо клиента (браузера).
Вышеупомянутая идея также верна для форм: браузеры не угадывают параметры, необходимые для заказа пиццы, они просто отображают форму и ее ввод и обрабатывают ее отправку.
Я видел слишком много строк кода во фронтэндах и бэкендах, которые строят строки
например -> "https://api.com" + "/order" - Вы не видите, что браузеры делают это, верно?
В приведенном выше примере (ответ «/books»), чтобы создать новую книгу, клиенты должны проанализировать ответ, чтобы использовать истинную мощь этого RESTful API, в противном случае они рискуют предположить, что имена полей какие из них требуются, каков их ожидаемый тип и т. д.
Теперь рассмотрите возможность наличия двух клиентов в вашей компании, использующих этот API. один для Интернета (браузеры), написанный на JS, а другой для мобильных устройств (скажем, приложение для Android), написанный на Java. Их можно публиковать в виде SDK, что, как мы надеемся, упростит интеграцию сторонним потребителям.
Как только API будет использоваться клиентами вне вашего контроля, скажем, сторонним разработчиком, знакомым с Python, с целью создания новой книги.
Этот разработчик ТРЕБУЕТСЯ проанализировать такой ответ, чтобы выяснить, что такое параметры, их имя, URL-адрес для отправки входных данных и так далее.
За все годы разработки я еще не сталкивался с API, подобным тому, который я имею в виду. У меня такое ощущение, что этот тип API — не более чем несбыточная мечта, и я надеялся понять, верны ли мои предположения и какие недостатки он приносит, прежде чем приступать к этапу реализации.
P.S. в случае, если это не ясно, это именно то, о чем HATEOAS-совместимый API-интерфейс - когда поля для создания книги меняются, клиенты адаптируются без нарушения.
Реализация API HATEOAS должна выполняться как на сервере, так и на клиентах, поэтому этот момент, который вы делаете в комментариях, действительно очень важен:
изменение URI ресурса рискованно, поскольку я не верю, что клиенты на самом деле «перемещаются» по API
Помимо всемирной паутины, которая является лучшей реализацией HATEOAS, я знаю только SunCloud API в ныне выведенном из эксплуатации Project Kenai. Большинство API-интерфейсов не совсем используют HATEOAS, а представляют собой просто набор документированных URL-адресов, по которым вы можете получать или отправлять определенные ресурсы (по сути, вместо того, чтобы «управляться гипермедиа», они «управляемы документацией»). С этим типом API клиенты на самом деле не перемещаются по API, они объединяют строки для перехода к определенным конечным точкам, где, как они знают, они могут найти определенные ресурсы.
Если вы предоставляете HATEOAS API, разработчики любых клиентов могут по-прежнему просматривать ссылки, которые вы возвращаете, и могут решить создать их самостоятельно, потому что они понимают, что делает API, а затем думают, что они могут просто обойти любую другую навигацию, которая может понадобится, и перейдите прямо к URL-адресу, потому что он всегда /products/categories/123
, пока, конечно, он больше не исчезнет.
API HATEOAS сложнее создать, и он усложняет работу как сервера, так и клиентов, поэтому при принятии решения о его создании возникают следующие вопросы:
В большинстве случаев ответ отрицательный. Кроме того, во многих случаях вопросы даже не задаются, вместо этого люди приходят к более знакомому подходу, потому что они видели, какие API люди создают, использовали или создавали раньше. Кроме того, во многих случаях REST API просто застревает перед базой данных и ничего не делает, кроме как предоставляет данные из базы данных в виде JSON или XML, поэтому там нет особой необходимости в навигации.
Вас никто не заставляет внедрять HATEOAS в свой API, и никто не запрещает вам это делать. В конце концов, нужно решить, хотите ли вы предоставлять свой API таким образом или нет (еще один пример: вы предоставляете свои ресурсы в виде JSON, XML или позволяете клиенту выбирать тип контента?).
В конце концов, всегда есть шанс сломать ваших клиентов, когда вы вносите изменения в свой API (HATEOAS или не HATEOAS), потому что вы не контролируете своих клиентов и не можете контролировать, насколько осведомлен разработчик клиента, насколько дисциплинирован или насколько хорошо они проделали работу по внедрению чужого API.
В Модели зрелости гипермедиа (HMM) пример, который вы приводите, находится на уровне 0. На этом уровне вы абсолютно правы в отношении проблем с этим подходом. Это много работы, и разработчики, вероятно, все равно будут игнорировать ее и жестко кодировать. Однако с универсальным типом мультимедиа с поддержкой гипермедиа вся эта дополнительная работа не только исчезает, но и фактически сокращает работу разработчиков.
Давайте сделаем шаг назад и рассмотрим, как работает Интернет. Есть три основных компонента: веб-сервер, веб-браузер и драйвер (обычно пользователь). Веб-сервер предоставляет HTML, который веб-браузер выполняет для представления графического пользовательского интерфейса, который драйвер может использовать для перехода по ссылкам и заполнения форм. Браузер использует HTML, чтобы полностью абстрагироваться от драйвера всех подробностей о том, как представить форму и как отправить ее по HTTP.
В мире API эта концепция универсального браузера, который абстрагируется от типа мультимедиа и деталей HTTP, еще не прижилась. Единственный, кого я знаю о таком и активном, и качественном, это Ketting. Использование такого браузера, как Ketting, устраняет всю ту дополнительную работу, которую разработчику пришлось бы проделать для использования всей этой гипермедиа. Браузер гипермедиа похож на SDK, который часто предоставляют поставщики API, за исключением того, что он работает для любого API. Теоретически вы можете ссылаться с одного API на другой, совершенно не связанный API. API больше не будут островами, они станут сетью.
Что делает браузеры гипермедиа возможными, так это типы мультимедиа общего назначения с поддержкой гипермедиа. HTML, конечно, самый успешный и известный пример, но есть и типы мультимедиа, основанные на JSON. Некоторые из наиболее широко используемых примеров — HAL и Siren.
Чем выше уровень медиа-типа в модели зрелости гипермедиа, тем больше общий браузер может сделать, чтобы абстрагироваться от медиа-типа, URI и деталей HTTP. Вот краткое объяснение. Ознакомьтесь с сообщением в блоге, указанным выше, для получения более подробной информации и примеров.
Уровень 0: на этом уровне гипермедиа кодируется специальным образом. Браузер мало что может с этим сделать, потому что каждый API может кодировать разные вещи. В лучшем случае браузер может использовать эвристику или ИИ, чтобы угадать, что что-то является ссылкой или формой, и обработать это как таковое, но обычно медиа-типы HMM уровня 0 предназначены для разработчиков, чтобы читать интерпретацию. Это приводит ко многим проблемам, которые вы определили в своем вопросе. Примеры: JSON и XML.
Уровень 1: На этом уровне ссылки являются первоклассной функцией. Тип носителя имеет четко определенный способ представления ссылки. Браузер однозначно знает, что следует интерпретировать как ссылку, и может предоставить интерфейс для перехода по этой ссылке, при этом пользователю не нужно беспокоиться об URI или HTTP. Этого достаточно для API только для чтения, но если нам нужно, чтобы пользователь ввел данные, у нас нет способа представить элемент управления гипермедиа, подобный форме. Человек должен прочитать документацию или специальное представление формы, чтобы знать, как отправлять данные. Примеры: HAL , RESTful JSON.
Уровень 2. На этом уровне формы (или элементы управления, похожие на формы) являются первоклассной функцией. Тип носителя имеет четко определенный способ представления элемента управления гипермедиа, похожего на форму. Браузер может использовать этот тип мультимедиа для выполнения таких действий, как создание HTML-формы, проверка пользовательского ввода, кодирование пользовательского ввода в приемлемый тип мультимедиа и выполнение HTTP-запроса с использованием соответствующего метода HTTP. Допустим, вы хотите изменить свой API для поддержки PATCH и предпочитаете, чтобы приложение начало использовать его, а не PUT. Если вы используете тип мультимедиа HMM уровня 2, вы можете изменить метод в представлении, и любое приложение, использующее браузер гипермедиа, который знает, как создать запрос PATCH, начнет отправлять PATCH вместо PUT без какого-либо вмешательства разработчика. Без типа носителя HMM уровня 2 вы застряли с этими PUT, пока не сможете получить все приложения, использующие ваш API, для обновления своего кода. Примеры: HTML, HAL-Forms , Siren , JSON Hyper-Schema , Uber , Mason , Collection+JSON.
Уровень 3: На этом уровне, в дополнение к элементам управления гипермедиа, данные также являются самоописываемыми. Помните те три основных компонента, о которых я упоминал? Последний, «драйвер», представляет собой основное различие между использованием гипермедиа в Интернете и использованием гипермедиа в API. В Интернете драйвером является человек (за исключением поисковых роботов для простоты), но с API драйвером является приложение. Люди могут интерпретировать значение того, что им преподносят, и иметь дело с изменениями. Приложения могут действовать на основе эвристики или даже искусственного интеллекта, но обычно они следуют фиксированной рутине. Если что-то изменится в данных, чего приложение не ожидало, приложение сломается. На этом уровне мы применяем семантику к данным, используя что-то вроде JSON-LD . Это позволяет нам создавать драйверы, которые лучше справляются с изменениями и даже могут принимать решения без вмешательства человека. Примеры: Гидра.
Я думаю, что единственным недостатком выбора использования гипермедиа в вашем API является то, что на большинстве языков нет готовых гипермедиа-браузеров HMM уровня 2. Но хорошая новость заключается в том, что одна реализация будет охватывать любой API, использующий поддерживаемый тип мультимедиа. Ketting будет работать для любого API и приложения, написанного на JavaScript. Потребуется всего несколько подобных реализаций, чтобы охватить все основные языки, и использование гипермедиа будет несложным выбором.
Другая причина выбора гипермедиа заключается в том, что это помогает в процессе проектирования API. Я лично использую JSON Hyper-Schema для быстрого прототипирования API и использую универсальный веб-клиент, чтобы переходить по ссылкам и формам, чтобы получить представление о рабочих процессах API. Даже если никто больше не использует схемы, для меня это стоит иметь, хотя бы на этапе проектирования.