8/7/2022

Магия декларативности и схемы. Часть 3: Полезные представления схемы

Что там было в прошлых сериях?

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

Теперь разберемся с полезностями для изучения схемы.

Напоминалка про пример

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

У нас уже есть готовый запрос

И схема

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

Мы уже знаем, что схема — это граф. Но погодите! В графе должны быть кружочки и стрелочки. А тут ничего такого нет. Непорядок! Исправить это досадное упущение поможет, например, graphql-voyager

Такое представление очень полезно для случаев, когда ваша схема хорошо мапится на бизнес-домен. Вы можете посмотреть на красивую картинку и увидеть связи между сущностями, о которых даже не подозревали. А если у вас есть распределенный граф (о нем я кратко расскажу в следующих постах), подобная визуализация поможет вам лучше понять, как устроена ваша система в целом.

Перед тем, как рассматривать красивости на основе схемы, разберемся с особым запросом к graphql движку – интроспекцией. Интроспекция — это такой же запрос, как и все остальные. Однако мы запрашиваем не данные, а информацию о схеме. Большинство инструментов могут работать как с результатом интроспекции, так и со схемой из graphql-файлика. Но некоторые инструменты требуют именно JSON с интроспекцией. Вот так мы можем скрафтить нужный JSON:


Для нашей схему получается вот такая красивая картиночка

Если предполагать, что схема хорошо мапится на предметную область, такое отображение может быть очень полезным.

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

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

Apollo studio — платформа, которая предоставляет множество фич для работы с графом

Мы еще несколько раз будем упоминать Apollo Studio по ходу повествования.

Но мы возьмем что-то более простое yarn add graphiql


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

GraphiQL
Query Variables
Request Headers
Documentation Explorer
No Schema Available
Не забывайте обновлять свои пакеты

Все версии graphiql ниже 1.4.7 имеют уязвимость для XSS атак. Поэтому не забывайте обновляться

Ранний отлов ошибок

Чем раньше мы находим ошибки, тем лучше. Именно поэтому мы так старательно настраиваем линтеры и тесты в наших проектах. Было бы круто отлавливать все невалидные запросы еще до того, как мы все закоммитили в репозиторий. И уж точно мы хотим найти ошибки до того, как наш код уехал на production :)

Давайте убедимся, что для этого у нас есть подходящий инструментарий:



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

  • настроить линтеры. Тут все уже придумали за нас. Вот этот пакет делает все, что нужно.
  • настроить расширение для вашей IDE. Для VS Code можно использовать вот это расширение. Для IDE от JetBrains есть вот такой замечательный плагин.
  • не забыть гонять эти проверки на CI. Тут нет ничего Graphql- или схема- специфического. Стандартный запуск линтеров.

У конфига для graphql инструментов есть свой стандарт. Поэтому, настраивая свой тулинг для IDE, загляните вот сюда.

Настраивайте небесящие хуки

Все легковесный линтеры и тесты удобно гонять на pre-commit hook. Если ваши проверки слишком тяжелые и занимают много времени, то лучше унести их куда-то еще. Хорошими кандидатами тут будут pre-push или проверки на CI.

Для нашего микропримера конфиг будет выглядеть примерно так:

// graphql.config.js
const path = require('path')

module.exports = {
  schema: path.join(__dirname, '/schema.graphql'),
}

В результате мы получим симпатичную подсветку синтаксиса

Поздний отлов ошибок.

Мы защитились линтерами и плагинами для IDE, но, разумеется, это не значит, что на production все будет гладко.

Что, если напишем вот такой код:

import { gql } from '@apollo/client'

const strangeDynamicQuery = (fieldName: string) => gql`
  query GetType {
      ${fieldName} {
        name
        description
      }
  }

Так как поле запроса fieldName передается динамически, линтеры не смогут обнаружить ошибку. Вы сразу потеряете все преимущества использования схемы. Я рекомендую не проделывать подобные трюки до тех пор, пока у вас нет полной уверенности в том, что вы делаете и зачем. Перед тем, как вы начнете писать динамические запросы, загляните в документацию. Возможно вы найдете другой, более простой и надежный способ решить свою задачу.

Вообще-то линтеры заметят

Для этого надо заменить тип string у аргумента fieldName на какой-то другой. Чуть позже, когда мы обсудим кодогенерацию, у вас должно появиться понимание, какой тип тут подойдет.

  • Мы задеплоили новую версию схемы, а часть клиентов сидит с открытыми браузерами. И там старая версия.

Все, что вы можете сделать на клиенте – поймать ошибку от сервера (хорошие новости: это будет объект с четко определенной структурой) и заслать ее, например в Sentry.

Искусство отлова

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

И это все?

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