# GraphQL

> Язык запросов к API и среда выполнения, в которых клиент сам описывает нужную структуру данных, а сервер возвращает ровно её; создан в Facebook.

Источник: https://llmdocs.ru/wiki/graphql/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Разработчик**: Facebook (Meta), с 2018 — GraphQL Foundation
- **Внутреннее использование**: 2012
- **Открыт**: 2015
- **Тип**: язык запросов и спецификация API
- **Транспорт**: обычно HTTP POST, подписки — WebSocket или SSE
- **Формат ответа**: JSON
- **Реализации**: Apollo, GraphQL Yoga, Hasura, Strawberry, gqlgen, Juniper
**GraphQL** — язык запросов к API и спецификация того, как сервер должен их выполнять. В отличие от [REST](https://llmdocs.ru/wiki/rest.md), где у каждого ресурса свой адрес и фиксированный формат ответа, в GraphQL обычно один адрес (`/graphql`), а клиент в запросе перечисляет именно те поля и связи, которые ему нужны. Сервер описывает свои данные **схемой** со строгими типами, проверяет запрос по ней и возвращает ответ в формате [JSON](https://llmdocs.ru/wiki/json.md) той же формы, что и запрос.

## История

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

## Схема

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

```graphql
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** — подписка на события в реальном времени.

## Запросы

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

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

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

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

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

Каждому полю схемы соответствует функция-**резолвер**, получающая родительский объект и аргументы. Сервер обходит запрос и вызывает резолверы, собирая ответ. Ошибки возвращаются в массиве `errors` рядом с частичными данными, а HTTP-код при этом часто остаётся 200 — непривычно для тех, кто ждёт стандартных [кодов состояния](https://llmdocs.ru/wiki/http-status-codes.md).[3]

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

## Сравнение с REST

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

GraphQL выигрывает в приложениях с разнообразными клиентами и сложными связанными данными. REST проще для публичных API, кэширования через [CDN](https://llmdocs.ru/wiki/cdn.md) и простых CRUD-сервисов. Ещё одна альтернатива для внутренних сервисов — gRPC.

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

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

- ограничение глубины и **стоимости** запроса;
- **persisted queries** — сервер выполняет только заранее зарегистрированные запросы по хешу;
- отключение интроспекции в продакшене для закрытых API;
- проверка прав доступа в каждом резолвере, а не только на входе (см. [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md));
- ограничение частоты запросов по стоимости, а не по их количеству.

## Экосистема

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

## См. также

- [REST](https://llmdocs.ru/wiki/rest.md)
- [HTTP](https://llmdocs.ru/wiki/http.md)
- [JSON](https://llmdocs.ru/wiki/json.md)
- [TypeScript](https://llmdocs.ru/wiki/typescript.md)

## Источники

1. [GraphQL — официальный сайт и документация](https://graphql.org/learn/)
2. [GraphQL Specification](https://spec.graphql.org/)
3. [GraphQL over HTTP (draft)](https://graphql.github.io/graphql-over-http/draft/)
4. [GraphQL — Security (graphql.org)](https://graphql.org/learn/security/)
5. [Apollo GraphQL Docs](https://www.apollographql.com/docs/)
6. [GitHub GraphQL API](https://docs.github.com/en/graphql)
