Интеграция приложений (API) ✳ Сайт системного аналитика
г. Старый Оскол
Войти
Сайт системного аналитика
Заказать звонок

Интеграция приложений (API)

Самые читаемые
21 июн 2023
21 июн 2023
21 июн 2023
12 дек 2022
28 ноя 2022
28 окт 2022
#Интеграция
Создание единой IT-инфраструктуры предполагает интеграцию приложений и данных, с помощью которых автоматизируется управление различными процессами. Интеграция не вызывает особых сложностей, когда речь идет о 2 информационных системах. Однако со временем IT-инфраструктура предприятия может усложняться, и интеграция уже трех и более автоматизированных систем, как и их совместная работа, может вызывать определенные трудности.

Интеграция приложений (API)

Введение

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

В ходе реализации интеграционного решения разработчики часто сталкиваются со следующими вызовами:

  • ненадёжность передачи данных по сети;
  • низкая скорость передачи данных;
  • технологические различия между интегрируемыми системами;
  • неизбежность изменений в интеграционных потоках между системами вследствие изменений в них.

Основные интеграционные подходы

Существует четыре основных интеграционных подхода (или стиля):

  • Файловый обмен. Исторически это самый ранний подход к интеграции, который отличается относительной простотой. Суть его в следующем: одно приложение создаёт файл, а другое приложение cчитывает данный файл.
    Приложения интегрирующиеся данным методом должны договориться об подходе к именованию файлов, их расположении, формате и процедуре удаления.
    Яркими примерами технологий, использующихся в данном типе интеграции, является FTP(s), NFS, HDFS (Hadoop), AWS S3 и IBM MQ File Transfer Edition.
  • Общая база данных. В этом подходе несколько информационных систем используют одну общую логическую структуру данных.
    Примеры технологий: Oracle, MS SQL Server, SAP HANA, MongoDB.
  • Удалённый вызов процедуры. Одно приложение предоставляет доступ к своей функциональности с помощью удалённого вызова процедуры.
    Примеры технологий: SOAP, Java RMI, .NET Remoting, JSON-RPC, XML-RPC, gRPC.
  • Асинхронный обмен сообщениями. Это, пожалуй, единственный из перечисленных подходов, который создавался специально для интеграции информационных систем. Одно приложение отправляет сообщение в специализированный для этих целей брокер сообщений, а другое приложение получает предназначенные для него сообщения через брокера.
    Идея концептуально похожа на работу электронной почты. Взаимодействие между приложениями осуществляется в асинхронном режиме, что подразумевает, что отправляющее приложение не должно ждать, пока сообщение дойдёт до получающего приложения, ждать пока оно будет обработано, сформирован ответ и т.д.
    Примеры технологий и продуктов: Apache ActiveMQ, RabbitMQ, IBM WebSphere MQ, NATS и TIBCO EMS

Группы классов интеграционных решений

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

  • Message Oriented Middleware (MOM)
  • Enterprise Service Bus (ESB)
  • Integration Platform as a Service (iPaaS)
  • Business Process Management (BPM)
  • API Management
  • Extract-Transform-Load (ETL)

API Management

Рассмотрим подробнее интеграционное решение API Management.

API Management – это относительно новый подкласс интеграционных решений, который концентрируется на публикации и управлении Web API (REST, SOAP, WebSockets).

API (Application Programming Interface – программный интерфейс приложения, или интерфейс программирования приложений) – специальный протокол для взаимодействия компьютерных программ, который позволяет использовать функции одного приложения внутри другого.

В общем, API обеспечивает взаимодействие между двумя системами. Это как винтик, связывающий две детали, или как шестеренка, при помощи которой приводятся в движение две соседние шестеренки.

Application Programming Interface

Основные задачи API Management

Основные задачи данного класса решений:

  • обеспечение безопасности (контроль доступа, защита от DDoS и т.п.);
  • управление трафиком;
  • аналитика использования Web API;
  • Business Process Management (BPM);
  • монетизация.

API часто получают данные из пользовательских интерфейсов. Джим Биссо, опытный технический писатель API в области Силиконовой долины, описал API, используя аналогию калькулятора компьютера. Когда нажимаем кнопки, скрытые функции взаимодействуют с другими компонентами для получения информации. Как только информация возвращается, калькулятор представляет данные обратно в графический интерфейс.

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

В конечном счете, разработчики вызывают API незримо для пользователя для извлечения информации в свои приложения. Кнопка в графическом интерфейсе пользователя программно подключена для вызова внешних служб. Например, кнопки VK или OK, которые взаимодействуют с социальными сетями, или видео Youtube, которые извлекают видео с youtube.com, работают под управлением веб-API.

Знание правил

Люди создают правила этикета, чтобы регламентировать взаимодействия между собой. Один из примеров — то, как мы разговариваем друг с другом по телефону. Представьте, что вы болтаете с подругой. Пока она говорит, вы знаете, что нужно молчать. Если она задаёт вопрос, а затем молчит, вы знаете, что она ждёт ответа и теперь ваша очередь говорить.

Компьютеры придерживаются аналогичного этикета, хотя и называется он термином «протокол».

Компьютерный протокол — это принятый набор правил, которые определяют, как два компьютера могут общаться друг с другом.

Однако по сравнению с нашими стандартами компьютерный протокол чрезвычайно строгий. Подумайте на минуту о двух предложениях: «Мой любимый цвет — синий» и «Синий — мой любимый цвет». Люди могут определить каждое предложение и понять, что они означают одно и то же, несмотря на то, что слова расположены в разном порядке. К сожалению, компьютеры не настолько умны.

Чтобы два компьютера могли эффективно взаимодействовать, сервер должен точно знать, как клиент будет структурировать свои сообщения. Представьте, что сервер – это человек, который просит почтовый адрес. Когда вы спрашиваете как определить место назначения, вы предполагаете, что первое, что вам скажут — это область, затем следуют город, улица, и, наконец, дом. У вас также есть определенные ожидания в отношении каждой части адреса, например, тот факт, что почтовый индекс должен состоять только из цифр. Похожий уровень точности нужен и для правильной работы компьютерного протокола.

Протокол интернета

В интернете основным протоколом является протокол передачи гипертекста, более известный под аббревиатурой HTTP (HyperText Transfer Protocol, протокол передачи гипертекста). Когда вы вводите адрес вроде http://example.com в веб-браузере, «http» указывает браузеру использовать правила HTTP-протокола при разговоре с сервером.

С повсеместным распространением HTTP в интернете многие компании предпочитают адаптировать его для использования в качестве протокола, лежащего в основе своих API-интерфейсов. Одним из преимуществ использования этого протокола является то, что он прост в изучении разработчиками.

Взаимодействие в HTTP основано на концепции, называемой Циклом «Запрос-Ответ». Клиент отправляет серверу запрос на выполнение каких-либо действий. Сервер, в свою очередь, отправляет клиенту ответ, в котором говорит, может ли он сделать то, что просил клиент.

HTTP протокол

Чтобы сделать правильный запрос, клиент должен указать четыре вещи:

  • URL (Unified Resource Locator, единый указатель ресурсов);
  • метод (Method);
  • список Заголовков (Headers);
  • тело (Body).

Может показаться, что тут слишком много всего чтобы просто передать сообщение, но помните, что компьютеры должны быть очень точными, чтобы общаться друг с другом.

URL

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

API развивают эту идею, добавляя в контекст URL такие объекты, как, например, клиенты, продукты и твиты. В результате URL-адреса становятся для клиента простым способом сообщить серверу, с каким объектом он хочет взаимодействовать. Конечно, API не называют их «объектами», им дают техническое название «ресурсы».

Метод (method)

Метод запроса сообщает серверу, какое действие клиент хочет, чтобы сервер предпринял. Фактически, метод обычно называют «глаголом» запроса.

В API-интерфейсах чаще всего встречаются четыре метода:

  • GET – просит сервер получить ресурс;
  • POST – просит сервер создать новый ресурс;
  • PUT – просит сервер отредактировать/обновить существующий ресурс;
  • DELETE – просит сервер удалить ресурс.

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

Ожидая своего заказа, вы делаете кучу запросов GET для проверки статуса. После часа ожидания вы решаете, что не готовы больше ждать, и делаете DELETE-запрос, чтобы отменить свой заказ.

Заголовки (Headers)

Заголовки HTTP (англ. HTTP Headers) — это строки в HTTP-сообщении, содержащие разделённую двоеточием пару имя-значение. Формат заголовков соответствует общему формату заголовков текстовых сетевых сообщений ARPA. Заголовки должны отделяться от тела сообщения хотя бы одной пустой строкой.

Все заголовки разделяются на четыре основных группы:

  • General Headers (Основные заголовки) – должны включаться в любое сообщение клиента и сервера;
  • Request Headers (Заголовки запроса) – используются только в запросах клиента;
  • Response Headers (Заголовки ответа) – только для ответов от сервера;
  • Entity Headers (Заголовки сущности) – сопровождают каждую сущность сообщения.
Именно в таком порядке рекомендуется посылать заголовки получателю.

Заголовки предоставляют метаинформацию о запросе. Это простой список элементов, таких как время отправки запроса клиентом и размер тела запроса.

Помните, как вы заходили со своего смартфона на веб-сайт, специально отформатированный для мобильных устройств? Это стало возможным благодаря HTTP-заголовку под названием «User-Agent». Клиент использует этот заголовок, чтобы сообщить серверу, какой тип устройства вы используете, и если веб-сайт достаточно умён чтобы прочесть его, то в результате отправит вам данные в наиболее удобном для вашего типа устройства формате.

Тело (Body)

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

Уникальной чертой тела является то, что клиент полностью контролирует эту часть запроса. В отличие от метода, URL-адреса или заголовков, где протокол HTTP требует жёсткой структуры, тело позволяет клиенту отправлять всё, что ему нужно.

Эти четыре части – URL, метод, заголовки и тело – составляют полный HTTP запрос.

Структура HTTP запроса
Структура HTTP запроса

HTTP-ответы

После того, как сервер получает запрос от клиента, он пытается выполнить запрос и отправить клиенту ответ. HTTP-ответы имеют очень похожую на запросы структуру. Основное отличие состоит в том, что вместо метода и URL-адреса ответ включает код состояния. А в остальном заголовки и тело ответа имеют тот же формат, что и запросы.

Структура ответа сервера HTTP
Структура ответа сервера HTTP

Коды состояний

Коды состояний — это трехзначные номера, каждый из которых подразумевает под собой уникальное значение состояния, обработанного сервером запроса. Если в API они используются корректно, эти три цифры могут сообщить очень много информации клиенту. Например, вы могли видеть эту страницу в период ваших интернет странствий:

Страница не найдена
Страница не найдена

Код состояния, связанный с этим ответом — 404, что означает «Не найдено». Всякий раз, когда клиент делает запрос на ресурс, который не существует, сервер отвечает кодом состояния 404, чтобы сообщить клиенту: «этот ресурс не существует, поэтому, пожалуйста, не запрашивайте его снова!»

В протоколе HTTP есть множество других статусов, от 200 («успешно! этот запрос был выполнен») до 503 («наш веб-сайт/API в настоящее время не работает»). Мы изучим некоторые из них чуть позже.

После того, как ответ доставлен клиенту, Цикл Запрос-Ответ завершается, и этот раунд связи завершается. Теперь клиент должен инициировать дальнейшее взаимодействие. Сервер не будет отправлять клиенту больше данных, пока он не получит новый запрос.

Как API строятся на HTTP?

Теперь вы понимаете, что HTTP поддерживает большое количество функциональных сочетаний, чтобы помочь клиенту и серверу общаться. Итак, как это помогает нам с API? Гибкость HTTP означает, что построенные на нём API могут предоставить клиентам большой бизнес-потенциал. Мы видели этот потенциал в приведённом выше примере заказа пиццы. Простое изменение метода запроса дало понять серверу, что нужно сделать: создать новый заказ или отменить существующий. Было легко превратить желаемый бизнес-результат в инструкцию, понятную серверу.

Эта универсальность протокола HTTP распространяется и на другие части запроса.

Некоторые API требуют наличия определенного заголовка, в то время как другим требуется конкретная информация внутри тела запроса. Возможность использования API зависит от понимания того, как сделать правильный HTTP-запрос, чтобы получить нужный вам результат.

Представление данных

При обмене данными с людьми возможности отображения информации ограничиваются только человеческой фантазией. Вспомните пиццерию — как она может оформить своё меню? Например, как текстовый список или маркированный список, может быть серией фотографий с подписями или только набором фотографий, на которые показывают посетители, чтобы оформить заказ.

Хорошо продуманный формат помогает целевой аудитории понимать информацию. Тот же принцип применяется при обмене данными между компьютерами. Один компьютер должен поместить данные в формат, понятный для другого. Обычно это какой-то текстовый формат.

Наиболее распространёнными форматами, встречающимися в современных API, являются:

  • JSON (JavaScript Object Notation, нотация объектов JavaScript);
  • XML (Extensible Markup Language, расширяемый язык разметки).

JSON

Многие новые API-интерфейсы приняли JSON в качестве формата, потому что он построен на популярном языке программирования Javascript, который повсеместно используется в интернете и применим как на фронте, так и на бэкенде веб-приложения или сервиса.

JSON – это очень простой формат, состоящий из двух частей: ключей (keys) и значений (values).

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

Посмотрим, как этот заказ пиццы может выглядеть в JSON:

{
  "crust": "original",
  "toppings": ["cheese", "pepperoni", "garlic"],
  "status": "cooking"
}

В приведенном выше примере JSON ключевыми словами являются слова слева: начинка, корочка и статус. Они говорят нам, какие атрибуты содержит заказ пиццы. Значения указаны в частях справа. Это фактические детали заказа.

Если вы прочитаете строку слева направо, вы получите довольно естественное английское предложение. Взяв, к примеру, первую строчку, мы могли бы прочитать её как «корочка для этой пиццы оригинального стиля». Вторая строка также может быть прочитана – в JSON значение, которое начинается и заканчивается квадратными скобками ([]), представляет собой список значений. Итак, мы читаем вторую строку заказа как «начинки для этого заказа: сыр, пепперони и чеснок».

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

{
  "crust": "original",
  "toppings": ["cheese", "pepperoni", "garlic"],
  "status": "cooking",
  "customer": {
      "name": "Brian",
      "phone": "546-452-102"
  }
}

В этой обновленной версии мы видим, что добавлен новый ключ «клиент». Значение этого ключа — это еще один набор ключей и значений, которые предоставляют подробную информацию о клиенте, разместившем заказ. Классный трюк, а?! Это называется Ассоциативным Массивом. Но не пугайтесь технического языка, ведь ассоциативный массив — это просто вложенный объект.

XML

XML существует с 1996 года. С возрастом он стал очень зрелым и мощным форматом данных. Как и JSON, XML предоставляет несколько простых строительных блоков, которые создатели API используют для структурирования своих данных.

Основной блок называется узлом (node).

Давайте посмотрим, как может выглядеть наш заказ пиццы в XML:

<order>
  <crust>original</crust>
  <toppings>
      <topping>cheese</topping>
      <topping>pepperoni</topping>
      <topping>garlic</topping>
  </toppings>
  <status>cooking</status>
</order>

XML всегда начинается с корневого узла, которым в нашем примере с пиццей является «заказ». Внутри заказа находятся ещё несколько «дочерних» узлов. Имя каждого узла сообщает нам атрибут заказа (как и ключ в JSON), а данные внутри представляют собой фактические детали (как и значение в JSON).

Вы также можете вывести предложения на английском языке, читая XML. Глядя на строчку с «корочкой», мы могли прочитать «корочка для пиццы оригинального стиля». Обратите внимание, как в XML каждый элемент в списке начинок обернут узлом. Как видите, формат XML требует гораздо больше текста для передачи, чем JSON.

Как форматы данных используются в HTTP

Теперь, когда мы изучили некоторые доступные форматы данных, нам нужно знать, как использовать их в HTTP. Для этого мы ещё раз поприветствуем одну из основ HTTP: заголовки. Мы узнали, что заголовки — это список информации о запросе или ответе. Есть заголовок, указывающий, в каком формате находятся данные: ContentType.

Когда клиент отправляет заголовок ContentType в запросе, он сообщает серверу, что данные в теле запроса отформатированы определённым способом. Если клиент хочет отправить серверу данные в формате JSON, он установит ContentType на «application/json». Получив запрос и увидев этот Content-Type, сервер сначала проверит, понимает ли он этот формат, и, если да, он будет знать, как читать данные.

Аналогичным образом, когда сервер отправляет клиенту ответ, он также устанавливает ContentType, чтобы сообщить клиенту, как читать тело ответа.

Иногда клиент может общаться только в одном формате данных. Если сервер отправляет обратно что-либо, кроме этого формата, клиент откажется и выдаст ошибку. К счастью, на помощь приходит второй HTTP-заголовок. Клиент может установить заголовок Accept, чтобы сообщить серверу, какие форматы данных он может принимать. Если клиент может общаться только в формате JSON, он может установить для заголовка Accept значение «application/json». И тогда сервер будет отправлять ответы в формате JSON. Если сервер не поддерживает формат, запрашиваемый клиентом, он может отправить клиенту сообщение об ошибке, чтобы сообщить ему, что запрос не будет работать.

С помощью этих двух заголовков, ContentType и Accept, клиент и сервер могут работать с форматами данных, которые они понимают и должны работать должным образом.

client-server.png

API, использующие протокол HTTP = веб-сервисы

«Веб-сервис» – это веб-приложение, предоставляющее ресурсы в формате, используемом другими компьютерами. Веб-сервисы включают в себя различные типы API, в том числе REST и SOAP API. Веб-сервисы – это, в основном, запросы и ответы между клиентами и серверами (компьютер запрашивает ресурс, а веб-сервис отвечает на запрос).

API, использующие протокол HTTP для передачи запросов и ответов, рассматриваются как «веб-сервисы». В случае веб-сервисов клиент, делающий запрос на ресурс, и сервер API, предоставляющий ответ, могут использовать любой язык программирования или платформу. Не имеет значения, какой язык программирования или платформа будут использоваться, потому что запрос сообщения и ответ сделаны через общий веб-протокол HTTP.

Веб-протокол является частью веб-сервисов: они независимы от языка и поэтому совместимы между различными платформами и системами. При документировании REST API не имеет значения, строят ли инженеры API с помощью Java, Ruby, Python или какого-либо другого языка. Запросы выполняются через HTTP, и ответы возвращаются через HTTP.

Рисунок ниже показывает общую модель REST API:

Клиент-сервер

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

Любой язык программирования, создающий запрос, будет по-своему отправлять вебзапрос и анализировать ответ на своем языке. Эти специфичные для языка функции отправки запросов и анализа ответов не являются частью REST API. REST API не зависит от языка и обрабатывает входящую и исходящую информацию по HTTP.

API-интерфейсы SOAP являются предшественниками REST API

До того, как REST стал самым популярным веб-сервисом, SOAP (Simple Object Access Protocol) был гораздо более распространенным. Чтобы лучше понять REST, полезно иметь некоторое понимание SOAP. Заодно и увидеть, что отличает SOAP и REST.

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

Файл WSDL определяет разрешенные элементы и атрибуты в обмениваемых сообщениях. Файл WSDL является машиночитаемым и используется серверами, взаимодействующими друг с другом для облегчения связи.

Сообщения SOAP заключены в «конверт», который включает в себя заголовок и тело, используя определенную схему XML и пространство имен.

Основная проблема с SOAP заключается в том, что формат сообщений XML слишком многословный и тяжелый. Особенно это проблематично в мобильных сценариях, где размер файла и пропускная способность играют решающее значение. Многословный формат сообщения замедляет время обработки, что делает взаимодействия SOAP вялым.

SOAP по-прежнему используется в enterprise приложениях (особенно в финансовых учреждениях) со связью server-to-server, но в последние годы SOAP вымещается REST, особенно для API открытых сетей

REST – стиль, а не стандарт

Как и SOAP, REST (Representational State Transfer) использует HTTP в качестве протокола передачи данных для запросов и ответов. Однако, в отличие от SOAP, REST является архитектурным стилем, а не стандартным протоколом. Вот почему REST API иногда называют RESTful API – REST – это общий стиль, которому следует API.

В архитектурном стиле нет ограничений XML в качестве формата сообщения. API REST могут использовать любой формат сообщений, который хотят использовать разработчики API, включая XML, JSON, Atom, RSS, CSV, HTML и другие.

Несмотря на разнообразие параметров формата сообщений, большинство API REST используют JSON (нотацию объектов JavaScript) в качестве формата сообщений по умолчанию. Они используют JSON, потому что он обеспечивает легкий, простой и более гибкий формат сообщений, который увеличивает скорость связи. Облегченная природа JSON также позволяет выполнять сценарии мобильной разработки и легок для парсинга в Интернете с помощью JavaScript.

Напротив, в XML, XSLT больше используется для представления или, скорее, «преобразования» («T» в XSLT) содержимого, хранящегося на языке XML. XSLT обеспечивает удобочитаемость (а не обработку данных, хранящихся в формате XML).

Фокус на ресурсах

Другой отличительной чертой REST является то, что API-интерфейсы REST фокусируются на ресурсах (то есть вещах, а не действиях) и способах доступа к ресурсам. Ресурсы, как правило, являются разными типами информации. Вы получаете доступ к ресурсам через URL (Uniform Resource Locators), так же как переход к URL-адресу в вашем браузере позволяет подключиться к информационному ресурсу. URL-адреса сопровождаются методом, который указывает, как вы хотите взаимодействовать с ресурсом.

REST фокусируется на ресурсах, доступ к которым осуществляется через URL.

Общие методы включают GET (чтение), POST (создание), PUT (обновление) и DELETE (удаление). Конечная точка обычно включает параметры запроса, которые определяют более подробную информацию о представлении ресурса, который нужно увидеть. Например, можно указать (в параметре запроса) ограничение на отображение 5 экземпляров ресурса.

Вот пример, как выглядит конечная точка:

Конечная точка показывает весь путь к ресурсу. Однако в документации вы обычно разделяете этот URL на более конкретные части:

  • Базовый путь (базовый URL или хост) относится к общему пути для API. В приведенном выше примере базовый путь – http://apiserver.com
  • Отношение конечной точки к конечному пути этой точки. В приведенном примере это /homes
  • ?limit=5&format=json – часть конечной точки содержит параметры строки запроса для этой точки

В приведенном выше примере конечная точка получит ресурс «homes» и ограничит результат до 5 домов. Будет возвращен ответ в формате JSON.

Можно иметь несколько конечных точек, которые ссылаются на один и тот же ресурс. Вот один из вариантов:

Приведенный выше URL-адрес может быть конечной точкой, которая извлекает домашний ресурс, содержащий определенный идентификатор. То, что передается обратно с сервера на клиент, является «представлением» ресурса. Ресурс может иметь много разных представлений (показывая все дома или дома, которые соответствуют определенным критериям, или дома в определенном формате и т.д.), Но здесь мы хотим видеть дом с определенным идентификатором.

Отношения между ресурсами и методами часто описывается в терминах «существительные» и «глаголы»

Ресурс - это существительное, потому что это объект или вещь

Глагол - это то, что вы делаете с этим существительным

Объединяя существительные с глаголами, вы формируете язык REST

Принципы REST

Каким образом REST может помочь нам достичь этих свойств и реализовать эти нефункциональные требования?

Чтобы это понять, давайте рассмотри 6 принципов REST – ограничений, которые и помогают нам добиться этих нефункциональных требований.

6 принципов REST:

  • клиент-серверная архитектура;
  • stateless;
  • кэширование;
  • единообразие интерфейса;
  • layered system;
  • code on demand.

Далее мы рассмотрим эти шесть принципов поподробнее.

Принцип 1. Клиент-серверная архитектура

Сама концепция клиент-серверной архитектуры заключается в разделении некоторых зон ответственности: в разделении функций клиента и сервера. Что это означает?

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

Что мы этим добиваемся и как могло бы быть иначе? Давайте представим, что клиент и сервер у нас объединены. Тогда, если мы говорим о мобильном приложении, каждое мобильное приложение каждого клиента должно было бы быть абсолютно самодостаточной единицей. И тогда, поскольку у нас единого сервера нет для получения/отправки информации, у нас получилась бы какая-то сеть единообразных компонентов – например, мобильные приложения общались бы друг с другом – такая распределённая сеть равноценных узлов.

Такие системы в реальной жизни есть и можно найти их примеры. Например, в блокчейне. Тем не менее, в случае с REST мы говорим о том, что разделяем ответственность. Например, отображение информации, её обработку и хранение.

Клиент-сервер

Также сервер может иметь базу данных (см. рисунок ниже). В данном случае надо понимать, что пара «сервер и БД» тоже будет парой «клиент-сервер». Только в данном случае сервером будет БД, а сам сервер — клиентом.

Клиент-серверная архитектрура

Что дает клиент-серверная архитектура и зачем она нужна?

Во-первых, клиент-серверная архитектура дает нам определённую масштабируемость: есть сервер, есть единая точка обработки запросов. При необходимости выдерживать большую нагрузку мы можем поставить несколько серверов. Также к нему можно подключать достаточно большое количество клиентов (сколько сможет выдержать). Таким образом, клиент-серверная архитектура позволяет добиться масштабируемости.

Во-вторых, REST даёт определённую простоту поддержки. Если мы хотим изменить логику обработки информации на сервере, то выполним эти изменения на сервере. В данном случае мы можем и не менять каждого клиента, как если бы они были абсолютно равноценной сетью.

Конечно, есть и минусы. В случае с клиент-серверной архитектурой мы понимаем, что у нас есть единая точка отказа в виде сервера. Если отказал сервер и у нас нет дополнительных инстансов, то для нас это будет означать неработоспособность системы.

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

Принцип 2. Stateless

Принцип заключается в том, что сервер не должен хранить у себя информацию о сессии с клиентом. Он должен в каждом запросе получать всю информацию для обработки.

Запрос прогноза погоды

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

Что мы делаем в случае, если мы работаем с Stateless? Мы отправляем запрос «Какая погода?», отправляем место, где хотим погоду узнать, и дату. Соответственно, прогноз погоды отвечает нам — «Будет пасмурно».

Если я захочу узнать, какая будет погода через день, то опять укажу место, где хочу узнать погоду, укажу другую дату. Сервер получит этот запрос, обработает и сообщит мне, что там уже будет очень переменная облачность.

Запрос прогноза погоды на следующий день

Что было бы, если бы у нас не было Stateless? В таком случае у нас бы был Stateful. В этом случае сервер хранит информацию о предыдущих обращениях клиента, хранит информацию о сессии, какую-то часть контекста взаимодействия с клиентом. А затем может использовать эту информацию при обработке следующих запросов.

Информация о предыдущих обращениях клиента

В этом случае у сервера хранится некоторый контекст. Он понимает, что я у него спрашиваю про 21-е число и могу дать ответ на основе информации, хранимой у него в БД или в кэше. Один из примеров, где можно встретить подход Stateful в жизни – это работа с FTP-сервером.

Вернёмся к Statless-подходу. Почему в REST-архитектуре мы должны использовать именно Statless-подход?

Плюсы Stateless
  • масштабируемость сервера;
  • уменьшение времени обработки запроса;
  • простота поддержки;
  • возможность использовать кэширование.

В первую очередь, это масштабирование сервера. Если каждый запрос содержит в себе абсолютно весь контекст, необходимый для обработки, то можно, например, клонировать сервер-обработчик: вместо одного поставить десять таких. Мне будет абсолютно неважно, в какой из этих клонов придёт запрос. Если бы они хранили состояние, то либо должны были синхронизироваться, либо мне нужно было бы умело направлять запрос в нужное место.

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

Также подход Stateless позволяет использовать кэширование.

Минусы Stateless

Какие проблемы может создать Stateless-подход?

  • усложнение логики клиента (именно на стороне клиента нам нужно хранить всю информацию о состоянии, о допустимых действиях, о недопустимых действиях и подобных вещах);
  • увеличение нагрузки на сеть (каждый раз мы передаём всю информацию, весь контекст. Таким образом, больше информации гоняем по сети).

В первую очередь, это масштабирование сервера. Если каждый запрос содержит в себе абсолютно весь контекст, необходимый для обработки, то можно, например, клонировать сервер-обработчик: вместо одного поставить десять таких. Мне будет абсолютно неважно, в какой из этих клонов придёт запрос. Если бы они хранили состояние, то либо должны были синхронизироваться, либо мне нужно было бы умело направлять запрос в нужное место.

Принцип 3. Кэширование

В оригинале этот принцип говорит нам о том, что каждый ответ сервера должен иметь пометку, можно ли его кэшировать.

Что такое кэширование?

Представим, что у нас всё так же есть сервис по прогнозу погоды, есть клиент, с которым взаимодействуют. Сам по себе этот сервис погоду не определяет. Погоду определяет метеостанция, с которой он связывается с помощью специальных удалённых вызовов. Что происходит, когда мы используем кэширование?

Например, клиент обратился к серверу с запросом «Хочу узнать погоду». Что делает сервер?

Если мы его только запустили и используем кэширование или если мы не используем кэширование вообще — сервер обратится к метеостанции, а она вернёт ему ответ. Перед тем, как сервер ответит клиенту, он должен сохранить эту информацию в кэше. И только потом вернуть ответ. Для чего?

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

Кэширование

Чего мы добились? Мы убрали одну часть взаимодействия между сервером и метеостанцией. Зачем нам это нужно? Это нужно и полезно, если у сервера часто запрашивают одинаковую информацию. Например, кэширование активно используется на новостных сайтах или в соцсетях (на веб-ресурсах, к которым происходит много обращений).

Какие у кэширования плюсы?

  • уменьшение количества сетевых взаимодействий;
  • уменьшение нагрузки на системы (не грузим их дополнительными запросами).

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

При этом важно понимать, что кэширование — это совсем не простая штука. Она бывает достаточно сложна и нетривиальна в реализации.

Также мы должны учитывать, что если отдаём какие-то данные, которые сохранили раньше, то важно помнить, что эти данные могли уже устареть.

В каких-то случаях это может быть приемлемо, но в каких-то случаях – абсолютно недопустимо. Соответственно, стоит ли использовать кэширование — всегда нужно обдумывать на конкретном примере.

Принцип 4. Единообразие интерфейса. HATEOAS

Hypermedia as the Engine of Application State (HATEOAS) — одно из ограничений REST, согласно которому сервер возвращает не только ресурс, но и его связи с другими ресурсами и действия, которые можно с ним совершить.

Рассмотрим пример. Возьмём HTTP-запрос, в котором я хочу получить определенный ресурс:

GET /accounts/12345/ HTTP/1.1 Host:bank.example.com
Accept: application/xml…

Здесь мы используем HTTP-глагол GET, то есть хотим получить ресурс. Обращаемся к некоторому счёту с номером 12345.

Что же предлагает HATEOAS? Если бы мы с учётом этого ограничения выполняли бы этот запрос, то в ответе получим не только информацию об этом объекте, но и все те действия, которые мы можем с ним совершить. И, если бы у него были бы какие-то важные связанные объекты, мы получили бы ещё и ссылки на них.

GET /accounts/12345/ HTTP/1.1 Host:bank.example.com
Accept: application/xml…

HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length:

<?xml version="1.0"?>
<account>
   <account_number>12345</account_number>
   <balance currency="usd">100.00<balance>
   <link rel="deposit" href="https://bank.example.com/accounts/12345/deposit" />
   <link rel="withdraw" href="https://bank.example.com/accounts/12345/withdraw" />
   <link rel="transfer" href="https://bank.example.com/accounts/12345/transfer" />
   <link rel="close" href="https://bank.example.com/accounts/12345/close" />
</account>

Получая такие ответы, клиент самостоятельно понимает, какие конкретные действия он может совершать над этим объектом и какую ещё информацию о связанных объектах он может получить. Мы даём клиентскому приложению намного больше информации и свободы действий. Логика клиента становится более гибкой, но при этом и более сложной.

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

В качестве обратной стороны медали мы получаем сильное усложнение логики, в первую очередь, клиента. Это может потянуть за собой и усложнение логики на сервере, потому что такие ответы нужно правильно формировать. Фактически ответственность за действия, которые совершает клиент, мы передаём на его же сторону. Мы ослабляем контроль валидности совершаемых операций на стороне сервера.

Принцип 5. Layered system (слоистая архитектура)

В предыдущих схемах мы рассматривали сторону клиента и сторону сервера, но не думали, что между ними могут быть посредники.

В реальной жизни между ними могут быть, к примеру, proxy-сервера, роутеры, балансировщики — все, что угодно. И то, по какому пути запрос проходит от клиента до сервера, мы часто не можем знать.

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

Слоистая архитектура

Знания балансировщика в этой схеме об участниках конкретно этой цепочки вызовов должны заканчиваться proxy-сервером слева и сервером справа. О клиенте он уже ничего не знает.

Минусы:

Увеличение нагрузки на сеть (больше участников и больше вызовов, чем если бы мы шли один раз от клиента до сервера напрямую).

Увеличение времени получения ответа (из-за появления дополнительных участников).

Принцип 6. Code on done (код по требованию)

Идея передачи некоторого исполняемого кода (по сути какой-то программы) от сервера клиенту.

Что это значит?

Код по требованию

Представьте, что клиент – это, например, обычный браузер. Клиент отправляет некоторый запрос и ждёт ответа – страницу с определённым интерактивом (например, должен появляться фейерверк в том месте, где пользователь кликает кнопкой мышки). Это всё может быть реализовано на стороне клиента.

Либо клиент, запрашивая данную страницу приветствия, получит в ответ от сервера не просто HTML-код для отображения, а ещё программу, которую он сам и исполнит. Получается, что сервер передаёт исходный код клиенту, а тот его выполняет.

Что мы за счёт этого получаем? Отчасти, это схоже с принципом HATEOAS. Мы позволяем клиенту стать гибче. Если мы захотим изменить цвет фейерверка, то нам не нужно вносить изменений на клиенте – мы можем сделать это на сервере, а затем передавать клиенту. Пример такого языка – javascript.

Взаимодействие между клиентом и сервером

В архитектуре REST клиенты отправляют запросы на поиск или изменение ресурсов, а серверы отправляют ответы на эти запросы. Давайте рассмотрим стандартные способы направления запросов и ответов.

Отправка запросов

REST требует, чтобы клиент сделал запрос на сервер для получения или изменения данных на сервере. Запрос состоит из:

  • НТТР-метода, который определяет вид операции;
  • заголовка, который позволяет клиенту передавать информацию о запросе;
  • пути к ресурсу;
  • необязательного тела сообщения, содержащего данные.
    • Мы используем в запросах для взаимодействия с ресурсами в системе REST 4 основных метода НТТР:

      • GET – получение конкретного ресурса (по id) или коллекцию ресурсов;
      • POST – создание нового ресурса;
      • PUT – обновление конкретного ресурса (по id);
      • DELETE – удаление конкретного ресурса по id.
        • В заголовке запроса клиент отправляет тип контента, который он может получить с сервера. Это поле называется Accept. Оно обеспечивает, что сервер не посылает данные, которые не могут быть поняты или обработаны клиентом. Параметры типов контента — это типы MIME (или Multipurpose Internet Mail Extensions).

          Типы MIME, используемые для указания типов контента в поле Accept, состоят из типа и подтипа. Они разделены слэшем (/).

          Например, текстовый файл, содержащий HTML, будет указан с типом text/html. Если этот текстовый файл содержит CSS, то он будет указан как text/css. Общий текстовый файл будет обозначаться как text/plain. Однако это значение по умолчанию, text/plain, не является исчерпывающим. Если клиент ожидает text/css, а получает text/plain, он не сможет распознать содержание.

          Другие типы и часто используемые подтипы:

          • image – image/png, image/jpeg, image/gif;
          • audio – audio/wav, audio/mpeg;
          • video – video/mp4, video/ogg;
          • application – application/json, application/pdf, application/xml, application/octet-stream.
            • Например, клиент, имеющий доступ к ресурсу с идентификатором 123 в ресурсе статей на сервере, может отправить запрос GET следующим образом:

              GET /news/123
              Accept: text/html, application/xhml

              В этом случае поле заголовка Accept говорит, что клиент примет содержание в text/html или application/xhtml.

              Запросы должны содержать путь к ресурсу, на котором должна выполняться операция. В RESTful API пути должны быть разработаны так, чтобы помочь клиенту понять, что происходит. Обычно первая часть пути должна быть множественной формой ресурса. Это позволяет легко читать и понимать вложенные пути.

              Пути должны содержать информацию, необходимую для определения местоположения ресурса с необходимой степенью конкретности. При ссылке на список или коллекцию ресурсов не всегда необходимо добавлять идентификатор. Например, запрос POST на путь somesite.com/persons не будет нуждаться в дополнительном идентификаторе, так как сервер генерирует идентификатор для нового объекта.

              В тех случаях, когда сервер отправляет клиенту полезную нагрузку, он должен включать тип контента в заголовок ответа. Это поле заголовка контента предупреждает клиента о типе данных, которые он посылает в теле ответа. Эти типы контента являются типами MIME, точно так же, как они находятся в поле Accept заголовка запроса. Тип контента, который сервер возвращает обратно в ответе, должен быть одним из параметров, указанных клиентом в поле принятия запроса.

              Например, клиент получает доступ к ресурсу с идентификатором 123 в разделе статей с этим запросом GET:

              GET /news/123 HTTP/1.1
              Accept: text/html, application/xhml

              Сервер должен отправить обратно контент с заголовком ответа:

              HTTP/1.1 200 (OK)
              Content-Type: text/html

              Это означает, что запрашиваемый контент возвращается в тело ответа с text/html – типом контента, который клиент будет в состоянии принять.

              Коды ответов

              Ответы от сервера содержат коды состояния для оповещения клиента об успехе операции.

              Для каждого метода НТТР ожидаются коды статуса, которые сервер должен вернуть в случае успеха:

              • GET – return 200 (OK);
              • POST – — return 201 (CREATED);
              • PUT – return 200 (OK);
              • DELETE – return 204 (NO CONTENT).
                • Если операция не работает, вернётся наиболее конкретный код состояния, соответствующий возникшей проблеме.

                  Предположим, у нас есть приложение, которое позволяет вам просматривать, создавать, редактировать и удалять клиентов и заказы для небольшого магазина одежды, размещенного на сайте somesite.com. Мы можем создать НТТР API, который позволит клиенту выполнять следующие функции.

                  Если бы мы хотели увидеть всех клиентов, запрос выглядел бы так:

                  GET http://somesite.com/persons
                  Accept:application/json

                  Возможный заголовок ответа будет выглядеть следующим образом:

                  Status Code: 200 (OK)
                  Content-Type: application/json

                  Затем следуют данные клиентов, запрошенные в формате application/json

                  Создание нового клиента путем размещения данных:

                  POST http://somesite.com/persons
                  Body:
                  {
                    "person": {
                        "name" = "Олег Лыков",
                        "email" = "avega@kma2.ru"
                    }
                  }

                  Затем сервер генерирует идентификатор этого объекта и возвращает его клиенту с таким заголовком:

                  201 (CREATED)
                  Content-Type: application/json

                  Для просмотра одного клиента мы используем метод GET, указывая идентификатор этого клиента:

                  GET http://somesite.com/persons/123
                  Accept:application/json

                  Возможный заголовок ответа будет выглядеть следующим образом:

                  Status Code: 200 (OK)
                  Content-Type: application/json

                  Затем следуют данные ресурса клиента с идентификатором 123 в формате application/json

                  Мы можем обновить этого клиента, вставив новые данные с помощью метода PUT:

                  PUT http://somesite.com/persons/123

                  Body:
                  {
                    "person": {
                        "name" = "Олег Лыков",
                        "email" = "avega@kma2.ru"
                    }
                  }

                  Возможный заголовок ответа будет иметь:

                  Status Code: 200 (OK)

                  чтобы сообщить клиенту, что элемент с идентификатором 123 был изменен.

                  Мы также можем УДАЛИТЬ этого клиента, указав его идентификатор:

                  DELETE http://somesite.com/persons/123

                  Ответ будет иметь заголовок, содержащий

                  Status Code: 204 (NO CONTENT)

                  уведомляющий клиента о том, что объект с идентификатором 123 был удалён и ничего в теле не осталось.