Потребителей можно сбить с толку, только если основательно изменить семантику одного из элементов управления, кардинально изменив тем самым его поведение, или если вообще удалить элемент управления. Применение таких элементов управления для разобщения клиента и сервера со временем приносит существенные выгоды, с лихвой компенсирующие небольшое повышение расхода времени, которое занимают оформление и выполнение используемых протоколов. Следуя по ссылкам, клиент получает возможность постепенного раскрытия API, что становится весьма удобным при реализации новых клиентов.
Одним из недостатков навигации по элементам управления является ее возможная многословность, поскольку клиенту для поиска нужной операции приходится следовать по ссылкам. В конечном счете это разумный компромисс. Я советую начать с обеспечения для клиентов возможности переходить по этим элементам, а чуть позже оптимизировать систему, если это потребуется. Следует помнить, что мы получаем большой объем уже готовой помощи от использования HTTP, о чем говорилось ранее. Вред от преждевременной оптимизации мы уже рассматривали, поэтому здесь развивать эту тему я не буду. Нужно также отметить, что для создания распределенных систем с гиперсредами было разработано множество подобных подходов и не все они могут нам подойти! Иногда вы можете поймать себя на мысли об ожидании хорошо зарекомендовавшего себя старомодного удаленного вызова процедур (RPC).
Лично я сторонник того, чтобы в качестве средства навигации по конечным точкам API предоставить потребителям не что иное, как ссылки.
Преимущества постепенного раскрытия API и уменьшения степени связанности могут стать весьма существенными аргументами. Тем не менее понятно, что не все можно реализовать, и я не вижу возможности повсеместного использования этой технологии, как бы мне этого ни хотелось. Я полагаю, что суть данного вопроса в том, что требуется некий авансовый задел, а награды за его создание зачастую приходят позже.
Применение стандартных текстовых форматов дает клиентам гибкость в потреблении ресурсов, а REST с использованием HTTP позволяет применять различные форматы. В ранее показанных примерах применялся XML, но на данном этапе намного более популярным форматом содержимого для сервисов, работающих с использованием HTTP, является JSON.
Тот факт, что JSON — намного более простой формат, означает, что его использование также дается проще. Сторонники этого формата также указывают на его относительную компактность по сравнению с XML как на еще один выигрышный фактор, хотя в реальности это не так уж и существенно.
Но у JSON есть и недостатки. В XML определяется элемент управления link, который ранее использовался нами в качестве элемента управления гиперсредой. В стандарте JSON ничего подобного не определяется, поэтому для содействия этой концепции часто используются внутренние стили. В прикладном гипертекстовом языке (Hypertext Application Language (HAL)) предпринимается попытка исправить ситуацию путем определения общих стандартов для создания гиперссылок в JSON (а также в XML, хотя XML, возможно, меньше нуждается в такой помощи). Если следовать стандарту HAL, то для выявления элементов управления гиперсредой можно воспользоваться такими инструментами, как HAL-браузер на веб-основе, который может существенно упростить задачу создания клиента.
Но мы, конечно же, не ограничены этими другими форматами. При желании через HTTP можно отправить практически все что угодно, даже двоичный код. Я все чаще и чаще вижу, как в качестве формата вместо XML используется просто HTML. Для некоторых интерфейсов HTML помогает убить сразу двух зайцев при его применении как в качестве пользовательского интерфейса, так и в качестве API, но при этом все же следует обойти ряд подводных камней, поскольку взаимодействие с человеком и с компьютером — слишком разные вещи! Но это, конечно, весьма привлекательная идея. В конце концов, для HTML существует множество парсеров.
Но лично я предпочитаю XML. У него более подходящая инструментальная поддержка. Например, когда нужно извлечь только вполне определенную часть полезной нагрузки (эта технология будет рассмотрена позже, в разделе «Управление версиями»). Можно воспользоваться XPATH — широко распространенным стандартом, который поддерживают многие инструментальные средства, или даже CSS-селекторами — их многие считают еще более простыми. При использовании JSON есть JSONPATH, но он не получил широкой поддержки. Я считаю странным, что люди выбирают JSON из-за его красоты и легкости применения, затем пытаются внедрить в него такие понятия, как элементы управления гиперсредой, которые уже имеются в XML. Но я понимаю, что, наверное, в данном вопросе отношусь к меньшинству и что JSON является форматом, который выбирает большинство!
С ростом популярности REST появились среды, помогающие создавать веб-сервисы RESTFul. Но в некоторых из них кроется слишком много компромиссов с краткосрочными приобретениями и долгосрочными проблемами. В попытке ускорить процесс эти среды могут потворствовать неприемлемому поведению. Например, некоторые среды действительно упрощают получение представления объектов, сформированных в базах данных, проводя их десериализацию в объекты, встроенные в процесс, после чего эти объекты выставляются на всеобщее обозрение. Я помню, как на конференции состоялся показ с использованием Spring Boot, где все это выдавалось за главное преимущество. Унаследованная связанность, провоцируемая такой системой, зачастую становится причиной куда более серьезных проблем, чем приложение усилий, необходимых для правильного разобщения этих представлений.
Здесь следует заняться решением более общей задачи. Нас в первую очередь должно интересовать решение вопроса о способах хранения данных и их показа потребителям. В одной из схем, увиденной мною и успешно применяемой одной из наших команд, предусматривалась задержка реализации должного постоянства микросервиса вплоть до достаточной стабилизации интерфейса. В промежуточный период образы просто сохранялись в файле на локальном диске, что, конечно же, не было подходящим долговременным решением. Тем самым гарантировалось, что решения по конструкции и реализации диктовались способом использования сервиса потребителями. В обосновании, подтвержденном результатами, утверждалось, что способ хранения объектов нашей предметной области в основном хранилище слишком легко и открыто влияет на те модели, которые посылаются по сети нашим сотрудникам. Одним из недостатков такого подхода является то, что мы откладываем работу, необходимую для подключения к сети хранилища данных. Но я полагаю, что для определения границ нового сервиса это вполне приемлемый компромисс.
Если говорить о простоте потребления, то создать клиентскую заглушку для REST с применением HTTP так же просто, как при использовании RPC, не удастся. Несомненно, факт применения HTTP означает, что при этом вы можете воспользоваться преимуществами великолепных клиентских библиотек HTTP, но если в качестве клиента вам потребуется реализовать и использовать элементы управления гиперсредой, то во многом придется рассчитывать на собственные силы. Лично я полагаю, что клиентские библиотеки могли бы справляться со своим предназначением намного лучше, чем сейчас, и, конечно же, сейчас они лучше, чем в прошлом, но я увидел, что их явное усложнение приводит к тому, что люди втайне склоняются к возврату к RPC с применением HTTP или создают общие клиентские библиотеки. Совместно используемый клиентом и сервером код может быть очень опасен, о чем будет говориться в разделе «DRY и риски повторного использования кода в мире микросервисов».
Еще одним негативным обстоятельством является то, что в некоторых средах веб-серверов фактически отсутствует качественная поддержка всех HTTP-глаголов. Это означает, что для вас может быть проще создать обработчик GET- или POST-запросов, но, чтобы добиться работы PUT- или DELETE-запросов, возможно, придется заняться прыжками через обруч. У надлежащих REST-сред, таких как Jersey, этих проблем не существует, и со всем этим можно нормально работать, но, если вы замкнуты на выбор конкретных сред, это может ограничить количество доступных для использования стилей REST.
Проблемой может стать также производительность. Полезная нагрузка REST с использованием HTTP может фактически быть более компактной, чем SOAP, поскольку здесь поддерживаются альтернативные форматы вроде JSON или даже двоичный код, но все же эта технология даже не приблизится к той лаконичности двоичного протокола, которая может быть предоставлена языком Thrift. Издержки HTTP для каждого запроса могут также стать проблемой для систем с требованиями малого времени ожидания.
Хотя технология HTTP может оказаться вполне подходящей при больших объемах трафика, с обменом данными, требующим малого времени ожидания, она справляется хуже, если сравнивать ее с альтернативными протоколами, являющимися надстройками над протоколом управления передачей (Transmission Control Protocol (TCP)), или с другими сетевыми технологиями. Несмотря на свое название, протокол WebSocket, к примеру, имеет очень мало общего с Web. После первоначального HTTP-квитирования он представляет собой простое TCP-соединение клиента и сервера, но при этом может стать намного более эффективным способом передачи потоковых данных для браузера. Если вас интересует именно это, следует заметить, что HTTP в нем используется по минимуму, не говоря уже о том, что он не имеет ничего общего с REST.
Для обмена данными между серверами, при котором особую важность приобретает малое время ожидания или малый размер сообщений, связь на основе HTTP вообще может показаться неприемлемой затеей. Для достижения желаемой производительности может понадобиться подобрать другие исходные протоколы, такие как протокол пользовательских датаграмм (User Datagram Protocol (UDP)), и многие RPC-среды будут вполне успешн