Всем привет! Меня зовут Денис Ребенок, я технический писатель в команде Deckhouse. В этом материале я хочу рассказать про документирование GraphQL API. Если документация на GraphQL API оформлена правильно, разработчики быстро находят ответы, грамотно подобранные примеры сразу работают, а структура понятна с первого взгляда.

В этой статье разберём:

  • что такое GraphQL API и каковы его отличия от REST-like API;

  • что такое GraphQL schema и как с ней работать;

  • как сделать документацию на GraphQL API красивой и удобной для восприятия;

  • как создавать статические справочники для GraphQL API;

  • что ещё можно и нужно документировать при документировании GraphQL API.

В конце статьи вы найдёте ссылку на репозиторий на GitHub, который можно скачать, развернуть у себя и использовать, чтобы потренироваться в документировании GraphQL API.

Что такое GraphQL и чем он отличается от REST

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

Чтобы легче понять, что такое GraphQL API, я сравню его с REST-like API — де-факто корпоративным стандартом, который используют многие и с которым знакомо большинство технических писателей.

Объём возвращаемых данных

В REST сервер обычно возвращает весь объект целиком, даже если клиенту нужны только отдельные поля. Например, при запросе информации о пользователе возвращаются все параметры: name, email, birthDate, address, friends, registrationDate и многое другое, даже если клиенту это не требуется.

Иногда в REST пытаются решить это разными способами. Например, через фильтрацию (добавление в запрос параметров вроде ?fields=name,email), которую нужно реализовать для каждого метода, либо через явные и неявные маски. Но это всё не является частью стандарта и реализуется в каждом API по-своему. Часто — в зависимости от используемого для реализации API языка программирования — это бывает сложно, дорого и не всегда оправдано.

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

Количество эндпоинтов (endpoints) и нейминг

Это следующее различие между GraphQL API и REST-like API.

В REST-like API существует множество разных эндпоинтов — свой под каждый запрос (операцию). Здесь для запросов используются разные HTTP-методы, такие как GET, POST, PUT, DELETE. И каждый запрос направляется на соответствующий эндпоинт.

В GraphQL API все запросы отправляются на один эндпоинт с использованием HTTP-метода POST, то есть используется одна конечная точка для всех операций. Но вопрос в том, как API-сервер понимает, что именно нужно клиенту: что-то получить, добавить или изменить какой-то объект. Здесь очень важно правильное именование запросов и операций.

Названия сделаны так, чтобы сразу было понятно, что выполняет тот или иной запрос: например, getAuthors означает «получить автора», createAuthors — «создать автора». Отправляются эти названия в теле запроса, там же указывается и тип оперции (query, mutation и пр.). Пример:

curl -X POST \
   -H "Content-Type: application/json" \
   -H "Authorization: Bearer your-token-here" \
   -d '{"query": "query { getAuthors { id name email } }"}' \   
   http://<host:port>/graphql/admin

Грамотный нейминг — обязательное условие при проектировании GraphQL API. И на документации, соответственно, это тоже отражается: понятные названия операций способствуют удобному восприятию документации и помогают быстро найти нужную информацию.

Получение всех связанных данных одним запросом

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

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

GraphQL schema: главный источник информации

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

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

Схема описывает все ключевые элементы API: типы данных (types), используемые в API, запросы (queries), мутации (mutations), подписки (subscriptions), а также аргументы (arguments), директивы (directives) и фрагменты (fragments). Разберём некоторые из них.

Типы данных

В GraphQL API типы описывают структуру и характеристики данных, с которыми можно работать через API. Существует несколько типов:

Объектные типы (object types) описывают объекты, которыми оперирует API (которые могут запрашиваться, создаваться, редактироваться или удаляться).

Каждый объект имеет поля определённого типа (скаляр или объект).

Пример описания объектного типа в схеме:

type User {
  id: ID!
  name: String!
  email: String!
  age: Int
  posts: [Post!]!
  createdAt: String!
}

Скалярные типы (scalar types), или скаляры, — аналоги примитивных типов в языках программирования. К ним относятся, например, String, Int и так далее.

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

Пример описания такого типа из официальной документации:

enum Episode {  
  NEWHOPE  
  EMPIRE 
  JEDI}

Объединения (unions) сочетают в себе несколько объектов разных типов.

Интерфейсы (interfaces) позволяют гибко работать с разными типами данных через один и тот же запрос.

Запросы

Запросы определяют, какие данные можно получить из API. Если сравнивать с тем же REST-like API, это аналог GET-запросов. Примеры нескольких запросов:

type Query  {
        getBooks: [Book]
        getBookById (bookId: ID!): Book 
        getBookByIsbn (bookIsbn:String!): Book
}

В этом примере описаны три запроса: получение списка книг, получение книги по ID и получение книги по ISBN.

Мутации

Мутации в GraphQL API определяют операции, которые изменяют данные на сервере. Это можно считать особым видом запроса, объединяющим в себе несколько типов запросов, используемых в REST-like API. Другими словами, мутации выполняют ту же роль, что и методы POST, PUT, PATCH или DELETE в REST API, то есть изменяют данные на сервере: создание, обновление, удаление. Пример:

type    Mutation   {
           createBook (bookInput:CreateBookInput!): Book!
           updateBook(bookId: ID!, bookInput:UpdateBookInput!): Book! 
           deleteBook(bookId:ID!): Book!
}

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

Подписки

Подписки позволяют клиентам подписываться на изменения данных на сервере в режиме реального времени:

type Subscription {
   bookCreated: Book
}

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

Пример GraphQL-схемы

Все перечисленные выше элементы (и не только) описываются в GraphQL-схеме. Вот небольшой пример:

type Author {
id: ID!
name: String! 
books: [Book!]!
}

input CreateAuthorInput {
name: String!
}

type Query {
getAuthors: [Author!]!
}

type Mutation {
createAuthor (authorInput:
CreateAuthorInput!): Author!
updateAuthor (authorId: ID!, authorInput:
UpdateAuthorInput!): Author!
}

И уже из этой схемы генерируется документация, отображаемая в графическом интерфейсе GraphiQL Playground.

Документация в GraphiQL Playground

GraphiQL Playground — интерактивный инструмент для тестирования и изучения схемы GraphQL API прямо в браузере. С его помощью можно выполнять запросы и сразу видеть результаты. И от техписа во многом зависит удобство работы с этим интерактивным инструментом.

Важно

Ранее мы говорили о GraphQL как о технологии и API, а теперь речь заходит о GraphiQL (перед QL добавлено «i») Playground — инструменте, в котором можно всё посмотреть и попробовать.

Комментарии для удобной работы с GraphiQL Playground

Чтобы документация отображалась в интерфейсе GraphiQL, в схему нужно добавить комментарии — и этим занимается технический писатель. В схеме GraphQL поддерживаются два типа комментариев:

Комментарии с решёткой (#). Они не отображаются в интерфейсе GraphQL API и могут использоваться для служебных целей, например для заметок разработчиков.

# Комментарий, которого не будет видно

Комментарии в тройных кавычках (""" … """). Это именно те комментарии, с которыми работает техпис. Они отображаются в GraphiQL Playground и поддерживают разметку CommonMark. Последнее значит, что в комментариях можно использовать жирный и курсивный текст, заголовки, ссылки, даже таблицы. Всё это красиво отрисуется в GraphQL Playground. Подробнее о разметке CommonMark читайте на официальном сайте.

"""Комментарий, который виден в документации"""
type Author {
        id: ID!
        name: String! 
        books: [Book!]!
}

Вот как комментарии в тройных кавычках выглядят в схеме — и именно из них генерируется документация:

А вот такой результат получается в самом GraphiQL Playground:

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

Примеры кода для GraphiQL Playground

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

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

Пример описания мутации в схеме GraphQL API с блоком кода:

Блоки кода значительно улучшают восприятие документации: она становится нагляднее и удобнее для чтения. Вот как приведённый выше комментарий с примером кода отрисуется в GraphiQL Playground:

Разработчик может скопировать такой блок, вставить его, например, в GraphiQL Playground и сразу попробовать, как всё работает.

Это позволяет сэкономить время на разборе того, как вообще строится тот или иной запрос.

Перед добавлением в схему блоков кода рекомендую их прогонять через GraphQL Formatter. Он находит любые ошибки и делает так, чтобы код красиво рендерился в интерфейсе GraphiQL Playground.

В коде можно сделать подсветку синтаксиса, чтобы в GraphiQL Playground это выглядело ещё понятнее и нагляднее:

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

Это вполне по силам техническому писателю. Интерфейс GraphiQL Playground генерируется на основе шаблона страницы — в нашем случае это шаблон на React. Его можно доработать, добавив подсветку кода.

Как именно реализовать подсветку — решать вам, исходя из потребностей и навыков. Например, можно написать собственный JavaScript-код, добавить нужные CSS- и HTML-правила прямо в шаблон — и всё будет корректно отображаться.

А можно воспользоваться готовым решением. Я, например, использовал библиотеку Prism. В ней можно указать языки, подсветку которых нужно поддерживать, после чего будут сгенерированы готовые фрагменты кода. Их достаточно скопировать, вставить в ваш шаблон генерации GraphiQL Playground — и документация начнёт отображаться с красивой и читаемой подсветкой синтаксиса.

Ещё можно добавить возможность копировать эти фрагменты одним нажатием кнопки. Представьте: пользователь кликает по кнопке, код сразу попадает в буфер обмена, он вставляет его в GraphiQL Playground — и всё работает.

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

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

  • воспользоваться готовым решением;

  • обратиться к своим коллегам — фронтендерам или разработчикам, чётко объяснив, чего вы хотите добиться.

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


Мы рассмотрели одну форму документирования GraphQL API — документацию, встроенную в GraphiQL Playground. Но иногда бывают ситуации, когда доступ к Playground пользователям не предоставляется: например, по требованиям безопасности или по другим причинам. Да и GraphiQL Playground может вообще не генерироваться при сборке API. В таких случаях нам на помощь приходит следующая форма документирования — статические сайты-справочники.

Статические сайты-справочники

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

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

Один из таких инструментов — SpectaQL. Он генерирует статические сайты на основе данных, полученных с помощью запроса интроспекции (Introspection queries) — ещё одна важная тема, которую техпису стоит изучить перед началом документирования GraphQL API.

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

Интроспекция в GraphQL

Интроспекция — это специальный GraphQL-запрос, который позволяет сразу получить всю информацию, содержащуюся в схеме: все типы данных, все query-запросы, мутации, подписки и так далее.

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

Сам запрос интроспекции может выглядеть довольно объёмно (на скриншоте лишь его малая часть):

На самом деле этот запрос не так страшен, как кажется: если уделить ему немного внимания, всё становится понятным и легко воспринимается.

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

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

Как генерировать документацию с помощью SpectaQL

Можно выделить два основных сценария генерации сайта-справочника с помощью SpectaQL.

Первый вариант — полная автоматизация.

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

Второй вариант — ручной подход.

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

Кастомизация сайта-справочника, созданного с помощью SpectaQL

Независимо от того, используется полная автоматизация или сборка вручную, технический писатель может кастомизировать внешний вид статического сайта. Так как SpectaQL — это Open Source-инструмент и вы работаете с его репозиторием напрямую, можно изменять его под свои нужды. Там есть всё необходимое — папки со стилями, скриптами, шаблонами. Вы это всё изменяете под себя и получаете статический сайт-справочник именно таким, каким хотите его видеть.

Что ещё документировать и как

Мы рассмотрели две основные формы документирования GraphQL API:

  • документацию, встроенную в схему и отображаемую в GraphiQL Playground;

  • документацию в виде статического сайта-справочника.

Однако мой опыт показывает, что этого может быть недостаточно.

Я рекомендую дополнить документацию следующими элементами (можно разместить их, например, в отдельном разделе портала документации):

1. Краткий обзор технологии. Объясните, что такое GraphQL, зачем он нужен и в чём его преимущества. Это особенно полезно для тех, кто с этой технологией раньше не сталкивался, — им будет проще «вкатиться».

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

3. Сравнения и аналогии с REST API или другими API, с которыми ваша команда работала ранее. На примере знакомых концепций новая технология усваивается значительно легче — пользователи быстрее понимают, как к ней подступиться.

4. Раздел с некоторыми концепциями API. Поговорим о них подробнее.

Концепции в GraphQL API, которые стоит описать в документации

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

Псевдонимы(aliases) позволяют переименовывать поля в ответе на запрос.

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

Фрагменты (fragments) — это способ вынести повторяющийся набор полей в отдельную конструкцию и многократно её использовать.

Представьте: вы запрашиваете много однотипных объектов, и для каждого пришлось бы перечислять один и тот же список полей ответа. Без фрагментов запрос стал бы громоздким и трудночитаемым. С фрагментами же он остаётся компактным и аккуратным.

Переменные (variables) позволяют выделять динамические значения в запросе и передавать их в запрос в виде отдельного словаря.

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

Директивы (directives) дают возможность динамически менять структуру запроса «на лету».

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

Если вы включите описание упомянутых выше «штук» в документацию — с пояснениями и примерами, — разработчики точно оценят вашу работу. Они будут довольны.

Где «пощупать» GraphQL API и набить руку в документировании

Перед тем как приступить к документированию GraphQL API, естественно, захочется «пощупать» эту технологию на реальных примерах. И это вполне возможно — потренироваться можно в нескольких местах:

  1. Официальный сайт GraphQL. На его страницах есть интерактивная документация: прямо в неё встроены редактируемые примеры запросов. Вы можете редактировать их и сразу видеть, как меняется результат. Это отличный способ «набить руку».

  2. Реальный GraphQL API от GitHub. Платформа уже давно использует GraphQL, вы можете войти под своим аккаунтом и выполнять запросы к своим репозиториям, проектам и профилю. Главное — действовать осторожно, чтобы случайно ничего не сломать или не удалить.

  3. Специальный тренировочный API — Rick and Morty API. Там вы не только потренируетесь строить запросы, но и заодно узнаете интересные факты о персонажах мультсериала. Однако учтите: в этом API работают только query-запросы, то есть получать данные можно, а мутации недоступны.

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

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

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

Скачивайте, тренируйтесь, прокачивайте навыки — и создавайте действительно крутую документацию для пользователей GraphQL API.

P. S.

Читайте также в нашем блоге:

Комментарии (0)