GraphQL

Материал из llmdocs — справочник разработчика
GraphQL
РазработчикFacebook (Meta), с 2018 — GraphQL Foundation
Внутреннее использование2012
Открыт2015
Типязык запросов и спецификация API
Транспортобычно HTTP POST, подписки — WebSocket или SSE
Формат ответаJSON
РеализацииApollo, GraphQL Yoga, Hasura, Strawberry, gqlgen, Juniper

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

История

Facebook начала использовать GraphQL в 2012 году для мобильных приложений: лента новостей требовала данных из множества источников, а REST-запросы на медленных мобильных сетях оказывались то избыточными, то недостаточными.[1] В 2015 году спецификацию и эталонную реализацию на JavaScript опубликовали, а в 2018 году проект передали независимому фонду GraphQL Foundation при Linux Foundation. Публичные GraphQL API предоставляют GitHub, Shopify, GitLab и многие другие.[6]

Схема

Схема пишется на языке SDL (Schema Definition Language):[2]

type User {
  id: ID!
  name: String!
  posts(first: Int = 10): [Post!]!
}

type Post {
  id: ID!
  title: String!
  author: User!
}

type Query {
  user(id: ID!): User
}

type Mutation {
  createPost(title: String!): Post!
}

! означает «не может быть null», [Post!]! — непустой список постов. Три корневых типа задают виды операций: Query — чтение, Mutation — изменение, Subscription — подписка на события в реальном времени.

Запросы

query {
  user(id: "42") {
    name
    posts(first: 3) {
      title
    }
  }
}

Ответ повторяет структуру запроса:

{"data": {"user": {"name": "Анна", "posts": [{"title": "Первый"}, {"title": "Второй"}]}}}

Так решаются две проблемы REST: over-fetching (ответ содержит лишние поля) и under-fetching (нужно несколько запросов, чтобы собрать связанные данные). Поддерживаются переменные, фрагменты для повторного использования наборов полей, псевдонимы и директивы @include/@skip. Схема доступна через интроспекцию, поэтому редакторы вроде GraphiQL подсказывают поля, а генераторы создают типы для TypeScript и других языков.

Как работает сервер

Каждому полю схемы соответствует функция-резолвер, получающая родительский объект и аргументы. Сервер обходит запрос и вызывает резолверы, собирая ответ. Ошибки возвращаются в массиве errors рядом с частичными данными, а HTTP-код при этом часто остаётся 200 — непривычно для тех, кто ждёт стандартных кодов состояния.[3]

Наивные резолверы порождают проблему N+1: запрос 50 постов с авторами выполнит 1 запрос за постами и 50 — за авторами. Её решают пакетной загрузкой (DataLoader), которая собирает ключи за один такт и делает один запрос к базе.

Сравнение с REST

REST GraphQL
Адреса много ресурсов обычно один
Форма ответа задаёт сервер задаёт клиент
Типизация по желанию (OpenAPI) обязательная схема
HTTP-кэширование естественное (GET, ETag) сложнее, нужен кэш на клиенте
Версионирование /v1, /v2 эволюция схемы, @deprecated
Загрузка файлов просто через расширения

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

Безопасность и производительность

Гибкость запросов открывает возможности для злоупотреблений: глубоко вложенный запрос может перегрузить сервер.[4] Обычные меры:

  • ограничение глубины и стоимости запроса;
  • persisted queries — сервер выполняет только заранее зарегистрированные запросы по хешу;
  • отключение интроспекции в продакшене для закрытых API;
  • проверка прав доступа в каждом резолвере, а не только на входе (см. Аутентификация и авторизация);
  • ограничение частоты запросов по стоимости, а не по их количеству.

Экосистема

  • Сервер: Apollo Server и GraphQL Yoga (Node.js), Strawberry и Graphene (Python), gqlgen (Go), Juniper и async-graphql (Rust), Hot Chocolate (.NET).
  • Клиент: Apollo Client, Relay, urql — с нормализованным кэшем.
  • Готовые API над базами: Hasura и PostGraphile генерируют GraphQL из схемы PostgreSQL.
  • Федерация: Apollo Federation объединяет схемы нескольких сервисов в один граф.[5]

См. также

Источники

  1. GraphQL — официальный сайт и документация
  2. GraphQL Specification
  3. GraphQL over HTTP (draft)
  4. GraphQL — Security (graphql.org)
  5. Apollo GraphQL Docs
  6. GitHub GraphQL API