Настройка схемы Graphql в Gatsby для новичков

У Gatsby есть одно существенное отличие от других фреймворков: он имеет встроенный слой данных Graphql. Такой слой открывает множество возможностей и является ключевой частью большой экосистемы плагинов. Вы можете получать данные из CMS с помощью Graphql, запрашивать изображения, запрашивать контент на основе markdown с помощью множества плагинов.

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

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

Что такое Gatsby’s Schema Customization API?

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

Примеры использования

Как начинающему пользователю, вам, вероятно, будет полезно использовать следующие общие сценарии:

  • Замена данных в существующем поле Graphql
  • Добавление нового поля к существующему типу Graphql и заполнение его некоторыми данными
  • Определение отношений между типами Graphql

Замена данных в существующем поле Graphql

Эта техника очень полезна, когда вы хотите определить значение по умолчанию для существующего поля. Например, у вас есть блог, в котором есть статьи, приходящие из markdown, и некоторые из них имеют флаг draft: true, а другие нет. Для лучшей фильтрации вы хотите убедиться, что каждая статья блога имеет поле draft со значением false или true в Graphql.

Есть два способа добиться этого. Первый — это использование API (документации) onCreateNode, который предоставляется Gatsby. Просто зайдите в gatsby-node.js и добавьте эти строки.

exports.onCreateNode = ({ node, actions }) => {
  const { createNodeField } = actions;

  if (node.frontmatter) {
    createNodeField({
      node,
      name: 'isDraft',
      value: node.frontmatter.isDraft || false,
    });
  }
};
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Для повышения производительности мы можем использовать более детальный подход, переопределив исходное поле с помощью пользовательского резольвера. Этот метод требует некоторых дополнительных знаний. Нам нужно знать точный тип Graphql, который мы хотим изменить. Чтобы узнать точное название типа, мы можем запустить Gatsby со специальным флагом GATSBY_GRAPHQL_IDE=playground npm start. Таким образом, мы увидим GraphQL Playground вместо GraphqiQL IDE на [http://localhost/__graphql](http://localhost/__graphql), и сможем получить необходимую информацию там.

Откройте панель Schema, найдите тип с помощью Ctrl+F. Найдя его, мы видим, что искомый тип — MdxFrontmatter, а поле isDraft имеет тип Boolean. Поэтому с помощью API createResolvers (docs), объявленного в gatsby-node.js, мы можем определить значение по умолчанию для поля.

exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    MdxFrontmatter: {
      isDraft: {
        type: 'Boolean',
        resolve: ({ isDraft }) => isDraft || false,
      },
    },
  });
};
Вход в полноэкранный режим Выход из полноэкранного режима

Как видите, в поле isDraft больше нет нулевых значений, и оно имеет значения false или true.

Добавьте новое поле к существующему типу Graphql и заполните его данными

Мы только что выяснили, как изменить существующие данные, но давайте пойдем дальше и добавим совершенно новое поле. Давайте рассмотрим пример с нашего сайта. У нас есть тематические исследования для проектов с открытым исходным кодом, хранящиеся в формате markdown, и мы хотим, чтобы во время сборки для каждого из них извлекалось количество звезд с GitHub. Это идеальная задача для настройки схемы Gatsby Graphql.

Итак, для каждого примера я хочу объявить поле githubStars и указать Gatsby на получение данных из GitHub API. Мы уже использовали функцию createResolvers для модификации поля, но она также может добавить новое поле.

Из Graphql Playground мы можем взять тип, используемый для файлов markdown, это будет Mdx, а затем добавить новое поле таким образом.

exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    Mdx: {
      githubStars: {
        type: 'String',
        resolve: async ({ frontmatter, fileAbsolutePath }) => {
          const { name, githubUsername, githubRepoName, isOpenSource } = frontmatter;

          if (
            fileAbsolutePath.includes('/case-studies/') &&
            isOpenSource &&
            githubUsername &&
            githubRepoName
          ) {
            try {
              const response = await fetch(
                `https://api.github.com/repos/${githubUsername}/${githubRepoName}`
              );
              const { stargazers_count } = await response.json();

              return new Intl.NumberFormat('en-US').format(stargazers_count);
            } catch (e) {
              throw new Error(`Failed to fetch GitHub stars for case study "${name}"`);
            }
          }
          return null;
        },
      },
    },
  });
};
Вход в полноэкранный режим Выход из полноэкранного режима

Функция Resolve получает все данные узла, поэтому легко фильтровать файлы mdx на основе определенных правил, например, по папке расположения файла. Resolver может быть асинхронной функцией, поэтому можно выполнять внешние вызовы и из нее.

Определение отношений между типами Graphql

Еще один распространенный случай использования. У вас есть блог в формате markdown, и у вас есть список авторов в JSON. Вы хотите получить все данные из слоя Graphql, чтобы автор был вложен в данные записи блога. Этого можно достичь с помощью хука createSchemaCustomization из gatsby-node.js, используя API createTypes (docs).

Структура объекта JSON author может быть такой:

/// content/posts/post-authors.json
[
  {
    "name": "Alex Barashkov",
    "photo": "../../src/images/post-authors/alex-barashkov.jpg",
    "description": "CEO at Pixel Point and software engineer with 10+ years of web development experience. Currently focused on React, Next.js, Gatsby.",
    "twitterUrl": "https://twitter.com/alex_barashkov"
  },
  ... more authors
]
Вход в полноэкранный режим Выход из полноэкранного режима

Однако содержание записи в блоге может выглядеть следующим образом:

// content/posts/example.md
---
title: 'Taking automated web page screenshots with Puppeteer and Sharp'
summary: A step-by-step tutorial on how to create perfect high-resolution web page screenshots automatically. No fuss, it just works.
author: Alex Barashkov
cover: cover.jpg
category: Development
---
... Blog post content
Войти в полноэкранный режим Выйти из полноэкранного режима

Как видите, у нас есть имя автора в данных поста frontmatter и то же имя в authors.json. Теперь задача состоит в том, чтобы сделать автора доступным через Graphql как вложенный объект, когда мы получаем данные поста.

Примечание: Для записей в блоге мы используем gatsby-plugin-mdx, для передачи JSON данных в Graphql — gatsby-transformer-json. Полный пример проекта можно посмотреть здесь.

Вот конфигурация из gatsby-config.js, которая обеспечивает этот соурсинг:

{
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'posts',
        path: `${__dirname}/content/posts`,
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'post-authors',
        path: `${__dirname}/content/posts/post-authors.json`,
      },
    },
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы используем ту же стратегию, что и раньше: давайте откроем Graphql Playground. Мы уже знаем тип файлов разметки Graphql, но нам нужно найти тип узлов на основе JSON. В нашем случае это будет PostAuthorsJson .

Имея эту информацию, мы можем добавить createSchemaCustomization в gatsby-node.js и использовать функцию под названием createTypes. Эта техника позволяет модифицировать схему Graphql.

Примечание: Если вы хотите полностью переопределить существующий тип Graphql, используйте директиву @dontInfer рядом с определением типа (docs).

Существует несколько вариантов определения вложенных отношений вручную. Однако самый простой вариант — использовать встроенную директиву @link. Думайте о ней как о помощнике, который выполняет отображение между двумя типами Graphql на основе предоставленных отношений внешних ключей.

Давайте проверим это. Добавьте этот код в gatsby-node.js и посмотрите на результат.

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions;
  createTypes(`
    type Mdx implements Node { 
      author: PostAuthorsJson @link(by: "name", from: "frontmatter.author")
    }
  `);
};
Войти в полноэкранный режим Выход из полноэкранного режима

Теперь авторы связаны с узлами разметки. Таким образом, вы можете получать вложенные данные и даже фильтровать результаты по информации об авторе.

Сводка

Теперь вы знаете, как изменить схему Gatsby Graphql, и я надеюсь, что вы найдете ее полезной для своего проекта. Все три примера доступны здесь, в нашем репозитории сайта на GitHub.

Если вы хотите узнать больше о Gatsby, Next.js, React и Headless CMS, следуйте за мной в Twitter.

Оцените статью
Procodings.ru
Добавить комментарий