Схема GraphQL
Схема GraphQL — это формальное описание типов данных, запросов и мутаций, которые поддерживает GraphQL-сервер. Она служит контрактом между клиентом и сервером, определяя, какие данные доступны для получения и изменения, а также в каком формате они могут быть запрошены. Схема является центральным элементом архитектуры GraphQL, обеспечивая строгую типизацию и самодокументирование API.
Основные понятия
Типы данных (Type System)
Схема GraphQL строится на системе типов. Каждый тип представляет собой набор полей, каждое из которых имеет собственный тип. Базовыми типами являются:
- Скалярные типы:
String,Int,Float,Boolean,ID(уникальный идентификатор). В GraphQL также можно определять пользовательские скалярные типы (например,Date). - Объектные типы (Object types): описывают сущности предметной области. Например, тип
Userможет содержать поляid,name,email. - Типы-перечисления (Enum types): задают фиксированный набор значений (например,
Status: ACTIVE, INACTIVE, BANNED). - Типы-интерфейсы (Interface types): определяют набор полей, которые должны быть реализованы другими типами. Позволяют запрашивать общие поля у разных типов.
- Типы-объединения (Union types): представляют собой набор типов, которые могут быть возвращены в ответе. Например,
SearchResultможет бытьUserилиPost. - Типы-входные данные (Input types): используются для передачи сложных аргументов в мутации или запросы. Они не могут содержать поля, которые являются объектными типами (только скаляры, перечисления и другие входные типы).
- Списки (List): обозначаются квадратными скобками (
[User]) и указывают, что поле возвращает массив значений. - Необязательные поля (Nullable/NonNull): по умолчанию поля могут быть
null. Для указания обязательности используется восклицательный знак (String!).
Корневые типы
Схема всегда содержит три корневых типа, которые определяют точки входа в API:
- Query: обязательный тип, описывающий все возможные запросы на чтение данных. Каждое поле в
Query— это точка входа для получения данных. - Mutation: необязательный тип, описывающий операции изменения данных (создание, обновление, удаление). Каждое поле в
Mutation— это точка входа для изменения данных. - Subscription: необязательный тип, описывающий операции подписки на реальном времени (например, получение уведомлений при изменении данных).
Пример корневого типа Query:
``graphql type Query { user(id: ID!): User users: [User!]! } ``
Аргументы и директивы
Поля в схеме могут принимать аргументы, которые уточняют запрос. Например, user(id: ID!) — аргумент id обязателен и имеет тип ID. Аргументы могут быть скалярными, перечислениями или входными типами.
Директивы — это аннотации, которые могут изменять поведение схемы или запроса. Встроенные директивы: @deprecated (указывает, что поле устарело), @skip и @include (используются в запросах для условного включения полей). Пользовательские директивы могут быть определены разработчиком.
Структура и синтаксис
Схема GraphQL записывается на языке определения схемы (SDL — Schema Definition Language). SDL использует простой синтаксис, похожий на GraphQL-запросы.
Определение типа
``graphql type User { id: ID! name: String! email: String posts: [Post!]! } ``
Определение корневого типа
``graphql type Query { user(id: ID!): User users: [User!]! } ``
Определение мутации
``graphql type Mutation { createUser(name: String!, email: String): User updateUser(id: ID!, name: String): User } ``
Определение подписки
``graphql type Subscription { userCreated: User } ``
Полная схема
```graphql schema { query: Query mutation: Mutation subscription: Subscription }
type User { id: ID! name: String! email: String posts: [Post!]! }
type Post { id: ID! title: String! content: String author: User! }
type Query { user(id: ID!): User users: [User!]! post(id: ID!): Post }
type Mutation { createUser(name: String!, email: String): User updateUser(id: ID!, name: String): User deleteUser(id: ID!): Boolean }
type Subscription { userCreated: User } ```
Принципы проектирования
Принцип единственной ответственности
Каждый тип должен представлять одну сущность или концепцию. Избегание «божественных» типов, содержащих все возможные поля.
Принцип обратной совместимости
Изменение схемы не должно ломать существующие клиенты. Добавление новых полей безопасно, удаление или изменение существующих — нет. Для пометки устаревших полей используется директива @deprecated.
Принцип гранулярности
Поля должны быть атомарными, чтобы клиент мог запросить только необходимые данные. Избегание полей, возвращающих сложные структуры без возможности фильтрации.
Принцип согласованности
Именование типов, полей и аргументов должно быть единообразным (обычно camelCase для полей, PascalCase для типов). Использование единого стиля для описания отношений.
Применение и значение
Документирование API
Схема GraphQL является самодокументируемой. Инструменты, такие как GraphiQL или GraphQL Playground, автоматически генерируют интерактивную документацию на основе схемы. Разработчики могут изучать доступные типы, поля и аргументы без необходимости читать внешнюю документацию.
Валидация запросов
Сервер GraphQL проверяет каждый входящий запрос на соответствие схеме. Если запрос содержит несуществующее поле, неправильный тип аргумента или нарушает правила, сервер возвращает ошибку. Это предотвращает выполнение некорректных запросов.
Типизация и безопасность
Строгая типизация схемы позволяет IDE (например, VS Code с расширением GraphQL) предоставлять автодополнение, проверку типов и подсветку ошибок на этапе написания кода. Это снижает количество ошибок времени выполнения.
Эволюция API
Схема позволяет постепенно развивать API, добавляя новые поля и типы, не нарушая работу существующих клиентов. Устаревшие поля помечаются директивой @deprecated, что даёт клиентам время на миграцию.
Примеры реализации
Реализация на Node.js (Apollo Server)
В экосистеме JavaScript схема может быть определена с помощью библиотеки Apollo Server. Пример:
```javascript const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql` type User { id: ID! name: String! email: String }
type Query { user(id: ID!): User } `;
const resolvers = { Query: { user: (parent, args) => { // логика получения пользователя } } };
const server = new ApolloServer({ typeDefs, resolvers }); server.listen().then(({ url }) => console.log(Server ready at ${url})); ```
Реализация на Python (Graphene)
В Python схема может быть определена с помощью библиотеки Graphene:
```python import graphene
class User(graphene.ObjectType): id = graphene.ID(required=True) name = graphene.String(required=True) email = graphene.String()
class Query(graphene.ObjectType): user = graphene.Field(User, id=graphene.ID(required=True))
def resolve_user(self, info, id):
логика получения пользователя
pass
schema = graphene.Schema(query=Query) ```
Интересные факты
- GraphQL был разработан компанией Facebook (организация Meta признана экстремистской и запрещена в РФ) в 2012 году для внутренних нужд, а в 2015 году был опубликован как открытый стандарт.
- Схема GraphQL может быть использована для генерации клиентского кода на различных языках программирования с помощью инструментов, таких как GraphQL Code Generator.
- Существует спецификация GraphQL, поддерживаемая GraphQL Foundation, которая определяет синтаксис и поведение схемы.
- Некоторые базы данных, такие как Dgraph и Fauna, имеют встроенную поддержку GraphQL, что позволяет использовать схему напрямую для запросов к данным.
Источники
- Спецификация GraphQL (GraphQL Foundation)
- Документация Apollo Server (Apollo GraphQL)
- Документация Graphene (Graphene-Python)
- Статья «GraphQL: A Query Language for APIs» (Lee Byron, Facebook, 2015)
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →