Открыть сервис

Типы данных GraphQL

Типы данных GraphQL — это система классификации значений, используемая в языке запросов GraphQL для описания структуры данных, которые могут быть запрошены или изменены через API. Каждый тип данных определяет набор допустимых полей, их типы и правила валидации, что обеспечивает строгую типизацию и предсказуемость взаимодействия между клиентом и сервером. GraphQL, разработанный компанией Meta (организация признана экстремистской и запрещена в РФ) в 2012 году и открытый в 2015 году, поддерживает как встроенные скалярные типы, так и пользовательские объектные, перечисляемые, интерфейсные и другие типы.

Основные категории типов

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

Скалярные типы

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

  • Int — целое число со знаком (32-битное, диапазон от -2^31 до 2^31-1). Пример: 42.
  • Float — число с плавающей точкой двойной точности (64-битное). Пример: 3.14.
  • String — строка символов в кодировке UTF-8. Пример: "Hello, World!".
  • Boolean — логическое значение, принимающее true или false.
  • IDуникальный идентификатор, часто используемый для первичных ключей. Сериализуется как строка, но не подлежит сравнению на равенство с другими строковыми типами.

Кроме встроенных, разработчики могут создавать пользовательские скалярные типы (например, Date, Email, JSON) для обработки специфических форматов данных. Для этого требуется определить сериализацию, десериализацию и валидацию в коде на стороне сервера.

Объектные типы

Объектный тип (ObjectType) — это наиболее распространённый пользовательский тип, который представляет собой набор полей, каждое из которых имеет свой тип (скалярный, другой объектный или список). Объектные типы описывают сущности предметной области, например, пользователя, статью или заказ. Пример определения в схеме GraphQL:

``graphql type User { id: ID! name: String! email: String posts: [Post] } ``

Здесь User — объектный тип с полями id (обязательное, тип ID), name (обязательное, тип String), email (необязательное) и posts (список объектов типа Post). Восклицательный знак (!) указывает на обязательность поля (non-null).

Перечисляемые типы

Перечисляемый тип (EnumType) — это тип, значения которого ограничены фиксированным набором строковых констант. Используется для полей, которые могут принимать только одно из нескольких предопределённых значений, например, статус заказа или роль пользователя. Пример:

``graphql enum OrderStatus { PENDING SHIPPED DELIVERED CANCELLED } ``

Поле status в объектном типе Order может быть определено как status: OrderStatus!. Перечисляемые типы улучшают читаемость кода и предотвращают ошибки ввода.

Списки и обязательные поля

Список (List) обозначается квадратными скобками ([Type]) и представляет собой массив значений указанного типа. Например, [String] — список строк, [User] — список объектов типа User. Списки могут быть вложенными (например, [[String]]).

Обязательное поле (non-null) обозначается восклицательным знаком (!) после типа. Если поле объявлено как String!, сервер гарантирует, что оно никогда не вернёт null. Если поле является списком, можно комбинировать: [String]! — список не может быть null, но может быть пустым; [String!]! — список не может быть null и ни один элемент в нём не может быть null.

Интерфейсы

Интерфейс (InterfaceType) — это абстрактный тип, который определяет набор полей, обязательных для реализации в объектных типах. Интерфейсы позволяют создавать полиморфные запросы, когда несколько типов имеют общие поля. Пример:

```graphql interface Node { id: ID! createdAt: String! }

type User implements Node { id: ID! createdAt: String! name: String! email: String }

type Post implements Node { id: ID! createdAt: String! title: String! content: String } ```

В запросе можно использовать встроенные фрагменты (... on User) для получения специфических полей в зависимости от фактического типа объекта.

Объединения

Объединение (UnionType) — это абстрактный тип, который может быть одним из нескольких объектных типов, но не требует общего набора полей (в отличие от интерфейсов). Объединения полезны для возврата разных типов из одного поля, например, результата поиска, который может содержать как пользователей, так и статьи. Пример:

```graphql union SearchResult = User | Post

type Query { search(query: String!): [SearchResult] } ```

При запросе объединения необходимо использовать фрагменты для указания конкретного типа: ... on User { name } ... on Post { title }.

Входные типы

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

```graphql input CreateUserInput { name: String! email: String! age: Int }

type Mutation { createUser(input: CreateUserInput!): User } ```

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

Система типов и схема

Вся система типов GraphQL описывается в схеме (schema), которая является единственным источником истины для API. Схема содержит определения всех типов, корневые типы (Query, Mutation, Subscription) и директивы. Корневые типы определяют точки входа для запросов (чтение данных), мутаций (изменение данных) и подписок (реактивное получение обновлений).

Директивы

Директивы — это аннотации, которые могут изменять поведение выполнения запроса или проверки типов. Встроенные директивы включают:

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

Пользовательские директивы могут быть реализованы на стороне сервера для таких задач, как аутентификация, кэширование или валидация.

Применение и преимущества

Типы данных GraphQL обеспечивают строгую контрактную модель взаимодействия между клиентом и сервером. Клиент может запрашивать только необходимые поля, а сервер гарантирует соответствие возвращаемых данных схеме. Это снижает количество ошибок, упрощает документирование (через инструменты вроде GraphiQL) и позволяет автоматически генерировать код для клиентских приложений (например, с помощью Apollo Client или Relay).

Система типов также поддерживает интроспекцию — возможность запрашивать саму схему через специальные поля __schema и __type. Это позволяет инструментам разработки автоматически отображать доступные типы, поля и их типы.

Ограничения и критика

Несмотря на преимущества, система типов GraphQL имеет ограничения. Например, отсутствие встроенной поддержки сложных числовых типов (например, Decimal) или кастомных типов дат требует реализации пользовательских скаляров. Кроме того, вложенные списки и глубокие объектные графы могут приводить к проблемам с производительностью (N+1 проблема), что решается с помощью инструментов пакетной загрузки данных, таких как DataLoader.

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

Источники

  1. GraphQL Specification (June 2018) — официальная спецификация языка.
  2. GraphQL: The Documentary (2018) — история создания и принципы.
  3. Документация Apollo GraphQL — практическое руководство по типам и схеме.
  4. Книга «Learning GraphQL» by Eve Porcello, Alex Banks (2018) — описание типов и их использования.
  5. Статья «GraphQL Schema Design» на сайте GraphQL.org — рекомендации по проектированию типов.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →