Пишем документацию API при помощи RAML
![Тирекс](https://selectel.ru/blog/wp-content/uploads/2023/05/T-Rex_Autor-3-400x400.png)
Удобство работы с любым API во многом зависит от того, как написана и оформлена его документация. Cейчас мы ведём работу по стандартизации и унификации описания всех наших API, и вопросы документирования для нас особенно актуальны. После долгих поисков мы решили оформлять документацию в формате RAML. Так называется специализированный язык для описания REST API. О его возможностях и преимуществах мы расскажем в этой статье.
![Изображение записи](https://selectel.ru/blog/wp-content/uploads/2015/08/PR-1267_preview.png)
Удобство работы с любым API во многом зависит от того, как написана и оформлена его документация. Cейчас мы ведём работу по стандартизации и унификации описания всех наших API, и вопросы документирования для нас особенно актуальны.
После долгих поисков мы решили оформлять документацию в формате RAML. Так называется специализированный язык для описания REST API. О его возможностях и преимуществах мы расскажем в этой статье.
Почему RAML
Как нужно документировать API? Вопрос этот не так прост, как может показаться на первый взгляд.
Первый и самый простой вариант, который приходит на ум — представить описание к API в виде обычного текстового документа. Так делают очень многие (в том числе и очень известные компании). Мы тоже не раз пользовались этим способом. При всей своей простоте он обладает следующими недостатками:
- текстовую документацию сложно поддерживать в актуальном состоянии;
- зачастую словесные описания API оказываются недостаточно наглядными;
- сфера использования «словесной» документации очень ограничена (например, на её основе нельзя сгенерировать интерактивную тестовую страницу).
Чтобы упростить процесс документирования, можно использовать специализированные инструменты и сервисы. Как правило, они генерируют документацию на основе описания в некотором стандартизованном формате — обычно это JSON или Markdown.
Ни один из этих форматов для написания документации не подходит. JSОN был изначально создан для обмена данными в вебе. При использовании его для других целей поневоле приходится прибегать к помощи «костылей» — например, кастомных полей, начинающихся со знака $. Кроме того, составлять описания в формате JSON вручную — дело достаточно рутинное и утомительное (в особенности если речь идёт об описаниях большого размера).
На описанные выше трудности обращали внимание многие пользователи популярного инструмента Swagger. Вскоре разработчики Swagger решили упростить работу по написанию спецификаций и создали фирменный редактор с поддержкой формата YAML.
Конечно, YAML гораздо удобнее, чем JSON. Но и его использование сопряжено с определёнными трудностями. Дело в том, что в описаниях API всегда имеются повторяющиеся элементы (например, схема ответа, которая может быть одинаковой для разных типов HTTP-запросов), которые приходится всякий раз прописывать вручную. Вот если бы можно их было раз и навсегда прописать в отдельном файле и ссылаться на него в случае небходимости…. Но, увы, пока что такой возможности нет.
Что касается формата Markdown (он используется, например, в API BluePrint), то предназначен в первую очередь для оформления текста, а не для использования в качестве основы для генерирования. Приспособить его под документирование API очень сложно. По этой же причине не привели к каким-либо заметным результатам попытки cоздать формат описания API на базе XML — например, язык WADL (Web Application Desription Language), разработанный компанией Sun Microsystems ещё в 2009 году, но так и не получивший широкого распространения.
Создатели проекта RAML (эта аббревиатура означает RESTful API Modeling Language — язык для моделирования REST API ) предприняли попытку разработать язык, предназначенный исключительно для описания API и исправить недочёты, свойственные другим форматам. Первая версия спецификации RAML была опубликована в 2013 году. Основным разработчиком RAML является компания MuleSoft; в проекте также принимают участие представители таких известных компаний, как Cisco, PayPal, ВoxInc. и других.
Несомненными преимуществами RAML являются:
- простой и логичный синтаксис, основанный на формате YAML;
- поддержка наследования и возможность подключения внешних файлов спецификаций.
Дополнительным плюсом является наличие большого количества конвертеров, парсеров и генераторов интерактивной документации. О некоторых из них мы расскажем ниже, а пока перейдём к обзору особенностей синтаксиса RAML.
Краткое введение в RAML
Структура документа
Файл спецификаций на RAML состоит из следующих структурных элементов:
- вводная часть («шапка»);
- схема безопасности;
- описание профилей;
- описание объектов и методов;
- описание ответов.
Рассмотрим эти элементы подробнее.
Вводная часть
Каждый документ на RAML начинается с вводной части, которая включает четыре обязательных элемента:
- версия RAML;
- имя документа;
- URI, по которому доступен API;
- версия API, описываемая в документации.
Выглядит это так:
#% RAML 0.8
title: Example API
baseUri: http://api.example.com/{version}
version: v1
Вводная часть может также включать различную дополнительную информацию — например, сведения об используемом протоколе для связи с API:
protocols: [http, https]
Можно во вводной части прописать и метаданные файла документации:
documentation
- title: Home
content: |
API Test Documentation
Схемы безопасности
Чтобы начать работать с любым API, нужно пройти процедуру авторизации. Она может осуществляться разными способами: через OAuth, с помощью токенов, либо посредством простой HTTP-аутентификации. Для описания этой процедуры в RAML используются схемы безопасности (security schemes).
Рассмотрим в качестве примера, как описывается авторизация с использованием протокола OAuth2:
#%RAML 0.8
title: Example API
version: 1
baseUri: https://api.example.com/{version}
securedBy: [oauth_2_0]
securitySchemes:
- oauth_2_0:
type: OAuth 2.0
describedBy:
headers:
Authorization:
type: string
queryParameters:
access_token:
type: string
responses:
401:
description: |
Bad or expired token.
403:
description: |
Bad OAuth request
settings:
authorizationUri: https://example.com/oauth/authorize
accessTokenUri: https://example.com/oauth/token
authorizationGrants: [ code, token ]
Приведённый фрагмент содержит следующую информацию:
- в параметре type указывается, что в API используется авторизация по протоколу OAuth2;
- далее указывается, что авторизационные данные можно передавать либо в заголовке Authorization, либо в query-параметре access_token;
- после этого следуют возможные коды ответов и их описания;
- в конце раздела, в секции settings указываются URL для авторизации, URL для получения токена, а также необходимые для аутентификации параметры (authorization grants).
Для удобства схемы безопасности можно сохранять в отдельных файлах .raml или .yml, и затем обращаться к ним в случае необходимости:
#%RAML 0.8
title: Example API
version: 1
baseUri: https://api.example.com/{version}
securedBy: [oauth_2_0]
securitySchemes:
- oauth_2_0: !include oauth_2_0.yml
Это помогает ускорить процесс документирования, избежать лишних повторений и сделать документацию менее громоздкой.
Почитать более подробно о схемах безопасности и ознакомиться с конкретными примерами можно здесь(раздел Security).
Объекты и методы
Далее перечисляются основные объекты и пути к ним, а также HTTP-методы, которые используются с этими объектами:
/document
get:
put:
post:
/{documentId}
get:
delete:
В приведённом примере описывается API, с помощью которого можно работать с документами. Мы можем скачивать документы на локальную машину (GET), изменять cуществующие документы (PUT) и загружать новые (POST). С каждым отдельным документом ({documentId}) мы можем также выполнять следующие операции: загрузка на локальную машину (GET) и удаление (DELETE).
HTTP-заголовки, используемые с тем или иным методом, описываются при помощи свойства headers, например:
/documents
get
headers:
X-Auth-Token:
required: true
Обратите внимание на свойство required: оно указывает, является ли заголовок обязательным (true) или необязательным (false).
В описании объектов и методов могут использоваться многочисленные дополнительные параметры. Рассмотрим следующий пример:
/document
/{documentId}
uriParameters:
id:
description: document identification number
type: string
pattern: ^[a-zA-Z]{2}\-[0-9a-zA-Z]{3}\-\d{2}\-\d{5}$
Здесь мы указываем, что каждый из документов, доступ к которым можно получить через API, имеет собственный идентификационный код в виде строки (type: string), а также описываем формат этого кода с помощью регулярных выражений.
Свойства description, type и pattern можно использовать и в описаниях методов, например:
/documents
get:
description: Retrieve a list of documents
post:
description: Add a new document
body:
application/x-www-form-urlencoded
formParameters:
id:
description: document identification number
type: string
pattern: [a-zA-Z]{2}\-[0-9a-zA-Z]{3}\-\d{2}\-\d{5}$
name:
description: the name of the document
type: string
required: true
author:
description: The name of the author
type: string
required: true
В описании метода POST мы указываем параметры, которые нужно передать в теле запроса для добавления нового документа: ID, имя и имя автора. Каждый из этих параметров является строкой (type: string). Обратите внимание на свойство required: оно указывает, является ли параметр обязательным (true) или необязательным (false).
Для каждого метода можно прописать индивидуальную схему безопасности:
/documents
get
[securedBy: oauth_2_0]
Query-параметры
Для каждого метода в документации можно указать query-параметры, которые будут использоваться в запросе. Для каждого query-параметра указываются следующие характеристики: имя, тип, описание и пример:
/document:
get:
queryParameters:
author:
displayName: Author
type: string
description: The author's full name
example: Ivan Petrov
required: false
name:
displayName: Document Name
type: string
description: The name of the document
example: Delivery contract
required: false
signingDate:
displayName: signingDate
type: date
description: The date when the document was signed
example: 2015-07-15
required: false
Профили
Чтобы избежать лишних повторений в описаниях, в RAML используются профили (traits), которые прописываются во вводной части документа:
#% RAML 0.8
title: Example API
baseUri: http://api.example.com/{version}
version: v1
traits:
- searchable:
queryParameters:
author:
displayName: Author
type: string
description: The author's full name
example: Ivan Petrov
required: false
name:
displayName: Document Name
type: string
description: The name of the document
example: Delivery contract
required: false
signingDate:
displayName: signingDate
type: date
description: The date when the document was signed
example: 2015-07-15
required: false
В дальнейшем к профилю можно обращаться при описании любых методов:
/document:
get:
is: [searchable]
Более подробно о профилях и особенностях их использования можно почитать в официальной документации (раздел Traits).
Описание ответа
В описании ответа обязательно указывается его код. Также в описание можно добавить схему (schema) — перечисление входящих в ответ параметров и их типов. Можно также привести пример конкретного ответа (example).
/documents:
/{documentId}:
get:
description: Retrieve document information
responses:
200:
body:
application/json:
schema |
{"$schema": “http://json-schema.org/schema”,
"type":"object"
"description": "a document"
"properties": {
"id":{"type":"string"}
"name":{"type":"string"}
"author":{"type":"string"}
"signingDate": {"type":"date"}
example: |
{"data:" {
"id": "DOC3456"
"name": "New Delivery Contract"
"author": "Ivan Petrov"
"signingDate": "2015-05-20"
},
"success": true
"status": 200
}
Cхемы ответов можно сохранять в отдельных файлах формата .yml или .raml и обращаться к ним в других частях документации:
schemas:
- !include document-schema.yaml
/articles:
get:
responses:
200:
body:
application/json:
schema: document
Визуализация и генерация документации
RAML2HTML и другие конвертеры
Несмотря на то, что RAML — формат относительно новый, для него уже разработано достаточное количество конвертеров и парсеров. В качестве примера можно привести ram2htmtl, генерирующий на основе описания в формате RAML статическую HTML-страницу.
Устанавливается он при помощи менеджера пакетов npm:
$ npm -i g raml2html
Чтобы сконвертировать RAML-файл в HTML, достаточно выполнить простую команду:
$ raml2html api.raml > index.html
Поддерживается возможность создания собственных шаблонов для HTML-файлов (подробнее об этом см. в документации на GitHub по ссылке выше).
Из других конвертеров рекомендуем также обратить внимание на RAML2Wiki и RAML2Swagger.
API Designer
Компания Mulesoft (один из активных участников проекта RAML) создала специальный онлайн-инструмент, с помощью которого можно упростить работу по написанию документации и последующему тестированию API. Называется он API Designer.
Чтобы начать им пользоваться, нужно сначала зарегистрироваться на сайте. После этого можно приступать к работе. API designer предоставляет, во-первых, удобный интерактивный редактор для написания документации онлайн, а во-вторых — платформу для тестирования.
Выглядит всё это так:
![API Designer](https://selectel.ru/blog/wp-content/uploads/2015/08/API-Designer.png)
В правой части страницы автоматически генерируется интерактивная документация. Здесь же можно и протестировать API: для этого достаточно просто развернуть описание нужного запроса и нажать на кнопку Try it.
API Designer позволяет также загружать RAML-файлы с локальной машины. Поддерживается импорт файлов описаний API для Swagger.
Кроме того, API Designer хранит статистику тестовыx запросов к API.
API console
API console — полезный инструмент, разработанный всё той же компанией MuleSoft. С его помощью можно прямо в браузере генерировать документацию к API. Файлы спецификаций можно как загрузить с локальной машины, так и указать ссылку на внешний источник:
![API Console](https://selectel.ru/blog/wp-content/uploads/2015/08/API-Console.png)
В состав API Console входит несколько файлов-образцов, представляющих собой описания API популярных веб-сервисов: Twitter, Instagram, Box.Com, LinkedIn. Мы попробовали сгенерировать на основе одного из низ документацию — выглядит вполне симпатично:
![API Console](https://selectel.ru/blog/wp-content/uploads/2015/08/API-Console1.png)
Документация, получаемая на выходе, является интерактивной: в ней можно не только прочитать описание API, но и выполнить тестовые запросы.
Заключение
В этой статье мы рассмотрели основные возможности RAML. Его несомненными преимуществами являются простота и логичность. Надеемся, что в скором будущем RAML получить ещё более широкое распространение и займёт достойное место в ряду инструментов для документирования API.
Если у вас есть вопросы — добро пожаловать в комментарии. Будем также рады, если вы поделитесь собственным опытом использования RAML на практике.