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

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 на практике.