Программный интерфейс приложения или API (Application Programming Interface) обеспечивает взаимодействие между двумя системами и позволяет через Веб-интерфейс обмениваться данными между клиентом, который посылает запрос, и сервисов, который отвечает на запрос.
Существует четыре различных способа работы API: SOAP, RPC, Websocket и REST, из которых последний REST API является наиболее популярным на сегодняшний день. REST (Representational State Transfer) использует HTTP в качестве протокола передачи данных для запросов и ответов. REST API в совокупности является больше архитектурным стилем, а не стандартом написания собственных сервисов. Тем не менее разработано несколько спецификаций REST API, из которых к самым популярным относят: OpenAPI, RAML и API Blueprint. В этой статье будет разбираться OpenAPI Specification.
OpenAPI спецификация (OAS, от OpenAPI Specification) определяет формализованный стандарт, который описывает интерфейс к REST API сервису и позволяет определять возможности REST-сервиса без доступа к его исходному коду или документации. Так как спецификация не зависит от выбора языка программирования, то, следовательно, является удобной в использовании как человеком, так и машиной.
Одним из способов взаимодействия Агента ПОДД с другими системами через СМЭВ4 является использование регламентированных REST-запросов, которые описываются посредством разработки и регистрации ИС поставщиком OAS в СМЭВ4 с дальнейшим его использованием ИС потребителя.
Полное описание формата разработки спецификации OAS можно найти на официальном сайте OpenAPI Specification. В текущей статье будут описаны основные особенности и рекомендации к написанию собственной спецификации OpenAPI для разработанной системы и в качестве примера спецификация будет описана для REST-сервиса, который будет выдавать информацию о регионах РФ.
Формат спецификации
Сам документ OAS представляет собой JSON объект, который может быть представлен в формате текстового файла JSON или YAML, последнее является более строгим и компактным синтаксисом JSON объекта. Все ниже приведенные примеры будут в формате JSON, так как конечный результат спецификации необходимо представить именно в таком стиле. Сам же сайт Swagger предоставляет веб-интерфейс для написания и редактирования OAS в формате YAML с последующей возможностью экспорта спецификации в JSON формат.
К основным терминам представления данных в формате JSON относят определения имени поля и его значение. Например, поле с именем field имеет числовое значение 3.0, как в следующем примере:
{"field": 3.0 } |
Стоит учитывать, что все имена полей в спецификации чувствительны к регистру. При этом стандарт спецификации OAS определяет два типа полей: это фиксированные или заранее определенные спецификацией имена полей, которые будут разобраны ниже и собственные имена полей, которые будут играть важную роль при использовании составленной спецификации (рекомендуется использовать строго латинские буквы).
Версия
Рекомендуемой версией к использованию спецификации является OpenAPI 3.0, которая значительно отличается от версии 2.0. Версия конкретной спецификации определяется полем openapi в начале каждого OAS документа.
Типы данных
К основным типам данных в OAS относят: integer, number, string и boolean. Типы данных так же имеют опциональное свойство формат, которое определяет более детальную информацию о типе.
Основная информация
Каждая написанная спецификация должна содержать в себе небольшой раздел метаданных в поле с названием info, которое будет описывать наименование, описание и версию конкретного документа.
{"title": "Регионы РФ", "description": "Информация о регионах Российской Федерации", "version": "1.0.0" } |
Компоненты
Не мало важной частью любой спецификации OpenAPI являются компоненты, которые описываются в поле с названием components в подразделе объекта shcemas. Под компонентами понимаются многократно переиспользуемые объекты для разных аспектов всей спецификации. Сами по себе компоненты не имеют никакого влияния на REST API интерфейс до тех пор, пока к ним явно не указано обращение из другой части документа.
В качестве компонента можно написать простую модель, которая будет описывать основные данные о регионе РФ. К таким данным отнесем уникальное значение записи (идентификатор), наименование, код региона и его краткое описание. Дополнительно укажем особо важные к заполнению параметры через required.
{"components": { "schemas": { "Region": { "required": [ "code", "id", "name" ], "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "code": { "type": "integer" }, "about": { "type": "string" } } } } } } |
Адреса
Прежде чем перейти к финальной части написания документа спецификации, стоит разобрать структуру итогового URL-запроса, по которому будет происходить обращение к OAS некоторого ИС поставщика.
Состоит такой запрос в первую очередь из сетевого адреса установленного Агента ПОДД, порта обращения к OpenAPI ПОДД, мнемоники ИС, которая обрабатывает запросы по собственной спецификации OpenAPI, заданного пути для обращения к сервису согласно заявки на регистрацию OAS и полной относительной части URL адреса, который описывается в спецификации.
{protocol}://{einfahrt}:{port}/{is_mnemonic}/{base_path}/{relative_path} |
Все относительные части запроса описываются в поле с именем paths. Такие запросы отделены друг от друга уникальным собственным именем поля, которое начинается с прямого слеша. В таком объекте описываются все возможные HTTP методы (GET, POST, PUT, DELETE и др.) и они содержат описательные характеристики и особенности составления такого обращения. Следующая часть является примером описания относительной части GET запроса для получения записи о регионе РФ по идентификатору.
{"/region/{id}": { "get": { "operationId": "regionById", "parameters": [ { "name": "id", "in": "path", "required": true, "style": "simple", "explode": false, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "Информация о регионе РФ", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Region" } } } }, "422": { "description": "Ошибка создания" } } } } } |
Стоит отметить важный параметр operationId в описании запроса, по которому ПОДД определяет уникальность каждого обращения к ИС поставщику.
По вышеизложенному примеру относительной части запроса, можно составить следующий URL адрес для ИС поставщика с мнемоникой MNEMONIC и заданного пути обращения mainPath:
http://localhost:8171/MNEMONIC/mainPath/region/1
Итоговая спецификация
В спецификацию можно добавить сколько угодно относительных адресов обращения к REST сервису и разбивать составляющие запросов на удобное количество компонентов. По результату написания спецификации можно увидеть следующий небольшой документ всего с тремя обращениями.
{"openapi": "3.0.0", "info": { "title": "Регионы РФ", "description": "Информация о регионах Российской Федерации", "version": "1.0" }, "paths": { "/region": { "post": { "operationId": "regionCreate", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegionPost" } } } }, "responses": { "200": { "description": "Данные о созданном регионе", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Region" } } } }, "422": { "description": "Ошибка создания" } } } }, "/region/{id}": { "get": { "operationId": "regionById", "parameters": [ { "name": "id", "in": "path", "required": true, "style": "simple", "explode": false, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "Информация о регионе РФ", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Region" } } } }, "422": { "description": "Ошибка создания" } } } }, "/regions": { "get": { "operationId": "regionsAll", "responses": { "200": { "description": "Данные о регионах", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Region" } } } } } } } } }, "components": { "schemas": { "Region": { "required": [ "code", "id", "name" ], "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "code": { "type": "integer" }, "about": { "type": "string" } } }, "RegionPost": { "type": "object", "properties": { "name": { "type": "string" }, "code": { "type": "integer" }, "about": { "type": "string" } } } } } } |