Задать вопрос
Все статьи / Полезная информация / Руководство по GraphQL для начинающих
Найти результаты:
Период:
с:
 
по:
Помощь в поиске

Помощь в поиске

apple banana
Найти записи, которые содержат хотя бы одно из двух слов.

+apple +juice
Найти записи, которые содержат оба слова.

+apple macintosh
Найти записи, которые содержат слово 'apple', но положение записей выше, если они также содержат 'macintosh'.

+apple -macintosh
Найти записи, которые содержат слово 'apple', но не 'macintosh'.

+apple ~macintosh
Найти записи, которые содержат слово 'apple', но если запись также содержит слово 'macintosh', rate it lower than if row does not. Это более "мягкий" чем поиск '+apple -macintosh', для которого наличие 'macintosh' вызывает что записи не будут возвращены вовсе.

+apple +(>turnover <strudel)
Найти записи, которые содержат слова 'apple' и 'turnover', или 'apple' и 'strudel' (в любом порядке), но ранг 'apple turnover' выше чем 'apple strudel'.

apple*
Найти записи, которые содержат такие слова как 'apple', 'apples', 'applesauce', или 'applet'.

"some words"
Найти записи, которые содержат точную фразу 'some words' (например записи содержащие 'some words of wisdom', но не "some noise words").

Руководство по GraphQL для начинающих

Для разработки современных приложений нужен не только удобный пользовательский интерфейс, но и эффективное взаимодействие между клиентом и сервером. Кроме того, часто хочется получать данные максимально гибко, экономя время и ресурсы. Решение всех этих проблем существует, и это GraphQL. 

В этой статье поговорим о том, что такое GraphQL, зачем он нужен и почему его все чаще выбирают разработчики.

Что такое GraphQL 

GraphQL — это язык запросов к данным и одновременно среда для выполнения этих запросов. Он был создан как альтернатива традиционным REST API. Вместо фиксированных маршрутов с заранее заданными структурами ответа, GraphQL позволяет клиенту самому указать, какие именно данные ему нужны и в каком виде. Все общение строится вокруг одной конечной точки (endpoint), а сами запросы выглядят как четко сформулированные структуры. 

GraphQL не привязан к конкретному языку программирования, и его можно использовать на сервере, написанном хоть на JavaScript, хоть на Python, хоть на Go. Самое важное — наличие схемы, которая описывает, какие данные вообще доступны и как их можно запрашивать.

В основе GraphQL лежит несколько ключевых принципов:

  1. Запросы по шаблону. Клиент описывает, какие поля и вложенные объекты ему требуются, отправляя этот запрос на сервер.
  2. Единая точка входа. Обычно достаточно одной конечной точки (например, /graphql), чтобы обращаться к различным данным.
  3. Гибкая структура. Можно в одном запросе запросить информацию сразу из нескольких связанных сущностей, что значительно упрощает получение комплексных данных.

В традиционном REST-подходе под каждую задачу могут быть свои конечные точки (/users, /posts, /comments и т.д.). С GraphQL же логика сводится к составлению нужного запроса, внутри которого уже описано, какие именно поля надо получить.

Особенности GraphQL 

  • Гибкость и точность запросов. В GraphQL клиент может самостоятельно формировать структуру запроса, точно указывая, какие именно данные и в каком объеме ему нужны. Благодаря этому решается проблема передачи лишних или ненужных данных, и работа приложения становится более эффективной. Например, если ему нужны только имена пользователей и их последние комментарии, можно запросить только эту информацию — сервер вернет именно ее и ничего лишнего.
  • Строгая типизация данных. GraphQL использует четкую схему, в которой прописаны все типы данных, поля и отношения между объектами. Это позволяет серверу сразу проверять корректность запросов и гарантировать, что клиент получит ответ именно того формата, который ожидает. Этот подход помогает быстро обнаруживать ошибки, а также упрощает сопровождение и развитие приложения.
  • Документация «из коробки». Еще одна удобная особенность GraphQL — встроенная документация. Поскольку описание API автоматически формируется из схемы, любое изменение тут же отражается в документации. Таким образом разработчикам не приходится вручную обновлять документацию, а клиентам гораздо проще понять возможности API и структуру доступных данных.
  • Объединение нескольких запросов в один. С GraphQL можно запрашивать одновременно разные типы информации за один запрос. Вместо нескольких отдельных запросов к разным REST-endpoint, клиент отправляет один комплексный запрос. Это значительно экономит сетевой трафик и улучшает общую производительность системы.
  • Поддержка подписок и обновлений в режиме реального времени. GraphQL предусматривает механизм подписок, благодаря которому клиенты могут получать уведомления и данные в реальном времени при изменении информации на сервере. Он полезен для создания динамичных, интерактивных приложений — чатов, новостных лент, систем уведомлений и других проектов с постоянно обновляющейся информацией.
  • Независимость от источников данных. GraphQL может собирать данные из множества разных источников: различных баз данных, внешних API и микросервисов. При этом клиентский запрос остается простым, а сервер самостоятельно собирает и объединяет всю необходимую информацию в единый ответ.

Ограничения GraphQL

  • Сложности с кешированием данных. GraphQL использует всего одну точку входа и запросы каждый раз имеют уникальную структуру. Из-за этого стандартные подходы к кешированию, привычные для REST-архитектуры, могут не сработать. Чтобы эффективно кешировать GraphQL-запросы, нужно использовать специализированные решения или разрабатывать собственные механизмы кеширования данных.
  • Возможная перегрузка серверов сложными запросами. Свобода клиента в формировании запросов несет риски. Например, клиент может случайно (или специально) сформировать очень сложный запрос, в которых входит большое количество вложенных данных и полей. Он может вызвать сильную нагрузку на сервер, повысить время ответа и потребление ресурсов. Для борьбы с этой проблемой необходимо внедрять механизмы защиты — например, ограничения глубины запросов, анализ сложности или таймауты.
  • Повышенные требования к безопасности. GraphQL по умолчанию предоставляет клиентам большие возможности для выборки данных. При неправильной настройке и отсутствии ограничений есть риск утечки информации и проведения атак. Например, злоумышленник может попытаться получить доступ к скрытым полям или выполнить массовый запрос данных, перегрузив сервер. Поэтому при внедрении GraphQL важно уделять особое внимание авторизации, проверке прав доступа и защите от атак.
  • Сложность реализации для крупных проектов. GraphQL отлично проявляет себя в новых проектах и приложениях среднего размера. Однако, если нужно внедрить его в уже существующий крупный проект со сложной REST-архитектурой и множеством устоявшихся процессов, внедрение может оказаться трудоемким и дорогостоящим. Понадобится много времени и сил на проектирование схемы, миграцию данных и адаптацию инфраструктуры.
  • Повышенная сложность мониторинга и аналитики. Из-за использования единой конечной точки и гибких запросов становится труднее отслеживать производительность, выявлять узкие места и ошибки в реальном времени. Чтобы решить это, необходимы специальные инструменты мониторинга, трассировки и логирования. Они смогут качественно отображать, что именно происходит внутри системы при выполнении GraphQL-запросов.

Принцип работы GraphQL

Работа GraphQL построена по схеме «запрос—ответ»:

  1. На сервере описана схема данных: какие сущности есть и как они связаны.
  2. Клиент формирует запрос, указывая, какие именно данные необходимы.
  3. Сервер принимает запрос, проверяет его соответствие схеме и запускает резолверы — функции, которые собирают данные.
  4. Сервер формирует ответ строго по запросу и отправляет его обратно клиенту.
  5. Клиент получает ответ и использует данные для отображения информации.

Теперь рассмотрим это на конкретном примере:

Все начинается с описания данных, которые можно получить через API. Для этого используется специальный язык — Schema Definition Language (SDL). Схема указывает, какие сущности доступны (например, авторы и книги), какие у них поля, какие данные обязательны, а также какие операции можно выполнять — например, запросить список книг или получить конкретную книгу по ID:

type Author {
  id: ID!
  name: String!
  books: [Book!]!
}
type Book {
  id: ID!
  title: String!
  publishedYear: Int!
  author: Author!
}
type Query {
  books: [Book!]!
  book(id: ID!): Book
}

В приведенном примере описаны два типа: Author и Book. У каждого автора есть идентификатор, имя и список книг, а у каждой книги — идентификатор, название, год публикации и ссылка на автора. Также определен тип Query, в котором можно либо получить список всех книг, либо одну книгу по ее ID.

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

query {
  book(id: "456") {
    title
    publishedYear
    author {
      name
    }
  }
}

В данном случае он запрашивает книгу с ID "456" и просит сервер вернуть только три поля: title, publishedYear и имя автора. Запрос выглядит компактно и читаемо: он сразу указывает, какие именно данные нужны, исключая все лишнее.

Затем клиент отправляет этот запрос на сервер, чаще всего через POST-запрос по HTTP. Сервер сначала проверяет, соответствует ли он описанной схеме. Если все корректно, сервер запускает специальные функции — резолверы — для каждого поля, указанного в запросе. 

Резолвер для запроса book(id: "456") обращается к базе и ищет книгу с указанным идентификатором. Далее, чтобы узнать автора этой книги, срабатывает другой резолвер, который по полю authorId находит нужного автора:

const resolvers = {
  Query: {
    book: async (_, { id }) => {
      return await db.findBookById(id);
    },
  },
  Book: {
    author: async (parent) => {
      return await db.findAuthorById(parent.authorId);
    },
  },
};

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

{
  "data": {
    "book": {
      "title": "Война и мир",
      "publishedYear": 1869,
      "author": {
        "name": "Лев Толстой"
      }
    }
  }
}

Основные компоненты запроса GraphQL

Чтобы лучше понять, как работает GraphQL, стоит ознакомиться с шестью ключевыми элементами запросов:

  • поля (fields);
  • аргументы (arguments);
  • переменные (variables);
  • фрагменты (fragments);
  • псевдонимы (aliases);
  • директивы (directives).

Разберем каждый подробно и с примерами.

Поля 

Поля — это конкретные данные, которые клиент запрашивает у сервера. Клиент указывает поля в фигурных скобках после имени запроса. Вложенные данные тоже запрашиваются полями.

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

{
  book(id: "456") {
    title
    publishedYear
    author {
      name
      nationality
    }
  }
}

Сервер вернет:

{
  "data": {
    "book": {
      "title": "Граф Монте-Кристо",
      "publishedYear": 1844,
      "author": {
        "name": "Александр Дюма",
        "nationality": "Франция"
      }
    }
  }
}

Аргументы 

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

В приведённом примере клиент запрашивает только три книги жанра «фантастика»:

{
  books(limit: 3, genre: "фантастика") {
    title
    author {
      name
    }
  }
}
Ответ сервера:
{
  "data": {
    "books": [
      {
        "title": "Солярис",
        "author": { "name": "Станислав Лем" }
      },
      {
        "title": "Дюна",
        "author": { "name": "Фрэнк Герберт" }
      },
      {
        "title": "Пикник на обочине",
        "author": { "name": "Аркадий и Борис Стругацкие" }
      }
    ]
  }
}

Переменные 

Переменные делают запросы динамическими. Вместо жестко заданных значений клиент передает их отдельно. Переменные объявляются в начале запроса и начинаются с символа $.

Пример:

query getBook($bookId: ID!) {
  book(id: $bookId) {
    title
    author {
      name
    }
  }
}
Они передаются в JSON-формате:
{
  "bookId": "789"
}

Фрагменты

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

Пример фрагмента:

fragment BookInfo on Book {
  id
  title
  publishedYear
}
Он объединяет повторяющиеся поля id, title и publishedYear.
В запросе фрагмент выглядит так:
{
  newestBooks {
    ...BookInfo
    author {
      name
    }
  }
}

Ответ сервера будет включать все поля из фрагмента и указанное отдельно поле author.

Псевдонимы

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

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

{
  firstBook: book(id: "1") {
    name: title
    year: publishedYear
  }
  secondBook: book(id: "2") {
    name: title
    year: publishedYear
  }
}
Ответ от сервера:
{
  "data": {
    "firstBook": {
      "name": "1984",
      "year": 1949
    },
    "secondBook": {
      "name": "О дивный новый мир",
      "year": 1932
    }
  }
}

Директивы 

Директивы позволяют управлять поведением запроса. Самые распространенные:

  • «@include(if: Boolean)» включает поле в результат, если условие истинно;
  • «@skip(if: Boolean)» исключает поле, если условие истинно;
  • «@deprecated(reason: String)» помечает поле как устаревшее.

Пример директивы в запросе:

query getAuthor($withBooks: Boolean!) {
  author(id: "5") {
    name
    books @include(if: $withBooks) {
      title
    }
  }
}

Если переменная $withBooks равна true, сервер вернет имя автора вместе с названием книг, иначе — только имя.

Как использовать GraphQL в веб-приложении: пошаговая инструкция

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

Рассмотрим подробно каждый этап этого процесса на простом примере приложения-блога:

Шаг 1. Создайте схему GraphQL

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

type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}
type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
  comments: [Comment!]!
}
type Comment {
  id: ID!
  text: String!
  author: User!
  post: Post!
}
type Query {
  users: [User!]!
  user(id: ID!): User
  posts: [Post!]!
  post(id: ID!): Post
}

Здесь мы задали три основных типа (User, Post, Comment) и тип Query, отвечающий за базовые запросы. Символ ! говорит о том, что поле обязательно.

Шаг 2. Подготовьте функции-резолверы

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

Пример простого резолвера для запроса всех постов:

const resolvers = {
  Query: {
    posts: async () => {
      // Получаем посты из базы данных или любого другого источника
      const posts = await db.getAllPosts();
      return posts;
    },
  },
  Post: {
    author: async (parent) => {
      return await db.getUserById(parent.authorId);
    },
    comments: async (parent) => {
      return await db.getCommentsByPostId(parent.id);
    },
  },
};

Здесь функция posts получает список постов, а функции в типе Post подгружают данные об авторе и комментариях конкретного поста.

Шаг 3. Настройте GraphQL-сервер

Есть множество библиотек для запуска GraphQL-сервера. Одна из самых популярных — Apollo Server. 

Как быстро поднять сервер с помощью Apollo:

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
const server = new ApolloServer({ typeDefs, resolvers });
server.listen({ port: 4000 }).then(({ url }) => {
  console.log(`GraphQL-сервер запущен по адресу: ${url}`);
});

После запуска сервера появится готовый GraphQL-эндпоинт (обычно http://localhost:4000), через который клиенты смогут отправлять запросы.

Шаг 4. Настройте GraphQL-клиент

Для работы с GraphQL на стороне клиента часто используют Apollo Client, который отлично интегрируется с React, Vue и другими популярными фронтенд-фреймворками.

Пример отправки запроса с помощью Apollo Client в простом JavaScript-приложении:

import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
  uri: 'http://localhost:4000',
  cache: new InMemoryCache(),
});
// Определяем GraphQL-запрос
const GET_POSTS = gql`
  query {
    posts {
      id
      title
      content
      author {
        id
        name
      }
      comments {
        id
        text
      }
    }
  }
`;
// Отправляем запрос и обрабатываем результат
client.query({ query: GET_POSTS })
  .then(result => {
    console.log(result.data.posts);
  })
  .catch(error => {
    console.error('Ошибка выполнения запроса:', error);
  });

В этом примере Apollo Client отправляет GraphQL-запрос серверу, а ответ отображается в консоли. Вместо множества отдельных REST-запросов получается один аккуратный и гибкий запрос, который существенно упрощает взаимодействие с сервером.

Заключение

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

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

Предыдущая статья
Работа с файлами и каталогами в Linux
Следующая статья
Системы управления базами данных: что такое СУБД и зачем они...