Что такое GraphQL?

GraphQL — язык запросов для API, разработанный Facebook (Meta) в 2012 году. В отличие от REST, где сервер определяет, какие данные возвращает каждый endpoint, GraphQL позволяет клиенту указать, какие именно поля ему нужны.

GraphQL vs. REST

ХарактеристикаRESTGraphQL
Endpoint-ыНесколько (/users, /posts)Один (/graphql)
Получение данныхСервер определяет структуруКлиент указывает поля
Over-fetchingЧастоИсключён
Under-fetchingТребует нескольких запросовРешено вложенными запросами
ВерсионированиеURL/заголовкиЭволюция схемы
КешированиеВстроенное HTTP-кешированиеСложнее

Основные концепции

Queries — чтение данных (аналог GET):

query {
  user(id: 42) {
    name
    email
    posts { title createdAt }
  }
}

Mutations — запись данных (аналог POST/PUT/DELETE):

mutation {
  createUser(input: { name: "Alice", email: "alice@example.com" }) {
    id
    name
  }
}

Subscriptions — обновления в реальном времени через WebSocket:

subscription {
  newMessage(chatId: "123") {
    content
    sender { name }
  }
}

Схема GraphQL

Схема определяет все доступные типы, queries и mutations:

type User {
  id: ID!
  name: String!
  email: String!
  role: Role!
  posts: [Post!]!
}

enum Role { ADMIN USER VIEWER }

type Query {
  user(id: ID!): User
  users(limit: Int, offset: Int): [User!]!
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}

! означает, что поле не может быть null. Интроспекция для исследования API:

{
  __schema {
    types { name fields { name type { name } } }
  }
}

Тестирование GraphQL-запросов

Тесты валидации запросов

ТестВводОжидание
Валидный запрос{ user(id: 42) { name } }200 с запрошенными полями
Несуществующее поле{ user(id: 42) { phone } }Ошибка: поле не найдено
Отсутствует обязательный аргумент{ user { name } }Ошибка: id обязателен
Неверный тип аргумента{ user(id: "abc") { name } }Ошибка: несоответствие типа
Пустой запрос{}Синтаксическая ошибка

Валидация ответа

  • Возвращаются только запрошенные поля
  • Non-nullable поля никогда не null
  • Типы массивов возвращают массивы (даже пустые)
  • Enum-значения соответствуют схеме

Тестирование Mutations

mutation {
  createUser(input: { name: "Alice", email: "alice@example.com", role: USER }) {
    id name email
  }
}

Тестовые сценарии для Mutations

СценарийОжидание
Валидный вводУспех с созданным ресурсом
Отсутствует обязательное полеОшибка валидации
Невалидное значение enumОшибка: невалидный Role
Дублирование уникального поляОшибка конфликта
Неавторизованная mutationОшибка аутентификации

Тестирование безопасности GraphQL

Атака глубиной запроса

{ user(id: 1) { posts { author { posts { author { posts { author { name } } } } } } } }

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

Атака сложностью запроса

{ users(limit: 10000) { posts(limit: 1000) { comments(limit: 1000) { author { name } } } } }

Тест: Проверьте применение лимитов сложности.

Отключение интроспекции в продакшне

{ __schema { types { name } } }

Тест: Проверьте, что запросы интроспекции не работают в продакшне.

Атака пакетными запросами

Тест: Проверьте лимиты пакетных запросов и применение rate limiting к пакетным операциям.

Инструменты тестирования GraphQL

ИнструментНазначение
GraphiQL / PlaygroundИнтерактивный обозреватель
PostmanПоддержка GraphQL-запросов
Altair GraphQL ClientПолнофункциональный клиент
graphql-inspectorDiff и валидация схемы

Практическое упражнение

  1. Исследуйте GraphQL API: Используйте Star Wars API GraphQL для отправки запросов и изучения схемы.
  2. Протестируйте mutations: С записываемым GraphQL API протестируйте CRUD-операции.
  3. Тестирование безопасности: Отправьте глубоко вложенные запросы и запросы интроспекции.
  4. Сравните REST vs GraphQL: Получите те же данные обоими подходами.

Ключевые выводы

  • GraphQL позволяет клиентам запрашивать именно нужные данные
  • Тестирование требует валидации queries, mutations, соответствия схеме и специфической безопасности
  • Лимиты глубины, сложности и отключённая интроспекция — критические меры безопасности
  • Проблема N+1 запросов — частая проблема производительности
  • Интроспекция полезна для проектирования тестов, но должна быть отключена в продакшне