Пишем документацию API при помощи RAML

Удобство работы с любым 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

В правой части страницы автоматически генерируется интерактивная документация. Здесь же можно и протестировать API: для этого достаточно просто развернуть описание нужного запроса и нажать на кнопку Try it.

API Designer позволяет также загружать RAML-файлы с локальной машины. Поддерживается импорт файлов описаний API для Swagger.
Кроме того, API Designer хранит статистику тестовыx запросов к API.

API console

API console — полезный инструмент, разработанный всё той же компанией MuleSoft. С его помощью можно прямо в браузере генерировать документацию к API. Файлы спецификаций можно как загрузить с локальной машины, так и указать ссылку на внешний источник:

API Console

В состав API Console входит несколько файлов-образцов, представляющих собой описания API популярных веб-сервисов: Twitter, Instagram, Box.Com, LinkedIn. Мы попробовали сгенерировать на основе одного из низ документацию — выглядит вполне симпатично:

API Console

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

Заключение

В этой статье мы рассмотрели основные возможности RAML. Его несомненными преимуществами являются простота и логичность. Надеемся, что в скором будущем RAML получить ещё более широкое распространение и займёт достойное место в ряду инструментов для документирования API.
Если у вас есть вопросы — добро пожаловать в комментарии. Будем также рады, если вы поделитесь собственным опытом использования RAML на практике.

Что еще почитать по теме

T-Rex 30 марта 2021

Что такое SMTP-протокол и как он устроен?

SMTP (Simple Mail Transfer Protocol) — протокол передачи почты. Он был представлен еще в 1982 году, но не теряет актуальности до сих пор. В статье разбираемся, какие задачи решает протокол и как он ра…
T-Rex 30 марта 2021
Владимир Туров 1 сентября 2020

Дело совершенно секретного iPod

Это был обычный серый день в конце 2005 года. Я сидел на рабочем месте и писал код для следующей версии iPod. Вдруг без стука ворвался директор ПО для iPod, начальник моего начальника, и закрыл дверь.
Владимир Туров 1 сентября 2020
T-Rex 21 августа 2020

TrendForce: цены на SSD упадут

Эксперты DRAMeXchange предсказывают значительное падение цен на оперативную память и твердотельные накопители в ближайшее время. Причина — сокращение спроса на чипы для NAND и DRAM.
T-Rex 21 августа 2020

Новое в блоге

Михаил Фомин 24 июня 2022

Docker Swarm VS Kubernetes — как бизнес выбирает оркестраторы

Рассказываем, для каких задач бизнесу больше подойдет Docker Swarm, а когда следует выбрать Kubernetes.
Михаил Фомин 24 июня 2022
Ульяна Малышева 30 сентября 2022

«Нулевой» локальный диск. Как мы запустили облако только с сетевыми дисками и приручили Ceph

Чем хороши сетевые диски и почему именно Ceph, рассказал директор по развитию ядра облачной платформы Иван Романько.
Ульяна Малышева 30 сентября 2022
Валентин Тимофеев 30 сентября 2022

Как проходит онбординг сотрудников ИТО? Что нужно, чтобы выйти на смену в дата-центр

Рассказываем, как обучаем новых сотрудников, какие задачи и испытания проходят инженеры прежде, чем выйти на свою первую смену.
Валентин Тимофеев 30 сентября 2022
T-Rex 28 сентября 2022

Книги по SQL: что почитать новичкам и специалистам

Собрали 6 книг, которые помогут на старте изучения SQL и при углублении в тему.
T-Rex 28 сентября 2022