Автор выбрал Фонд свободного и открытого исходного кода для получения пожертвования в рамках программы Write for DOnations.
Введение
GraphQL – современное решение для облегчения коммуникации между фронтендом и источником данных. Все детали и возможности реализации GraphQL описаны в схеме GraphQL (Schema). Для написания работающей схемы GraphQL необходимо понимание типовой системы GraphQL.
В этой статье вы узнаете о типах GraphQL: пяти встроенных скалярных типах, перечислениях (Enums), обертках List и Non-Null, типах объектов и абстрактных интерфейсах и объединенных типах (Union), работающих вместе с ними. Вы рассмотрите примеры каждого типа и узнаете, как использовать их для создания полной схемы GraphQL.
Предварительные условия
Чтобы извлечь максимальную пользу из этого руководства, вам следует иметь:
- Понимание основных концепций GraphQL, которые изложены в Введение в GraphQL.
- A GraphQL environment, an example of which can be found in How to Set Up a GraphQL API Server in Node.js.
Скалярные типы
Вся информация в схеме GraphQL в конечном итоге сводится к различным скалярным типам, которые представляют примитивные значения. Ответы GraphQL могут быть представлены в виде дерева, а скалярные типы являются листьями в конце дерева. В ответе с множественными уровнями вложенности может быть много уровней, но последний уровень всегда сводится к скалярному (или перечислению) типу. GraphQL поставляется с пятью встроенными скалярными типами: Int
, Float
, String
, Boolean
и ID
.
Int
Int
– это знаковое 32-битное целочисленное значение без дробной части. Это знаковый (положительный или отрицательный) целочисленный тип, который не содержит десятичных дробей. Максимальное значение знакового 32-битного целого числа – 2 147 483 647
. Это один из двух встроенных скалярных типов, используемых для числовых данных.
Float
– это числовое значение с плавающей точкой. Оно представляет собой число с десятичной точкой, которое может быть как положительным, так и отрицательным.
A Float
is a signed double-precision fractional value. It is a signed (positive or negative) number that contains a decimal point, such as 1.2
. This is the other built-in scalar used for numerical data.
String
– это текстовая строка. Он представляет собой последовательность символов, которая может включать буквы, цифры и специальные символы.
A String
is a UTF-8 character sequence. The String
type is used for any textual data. This can also include data like very large numbers. Most custom scalars will be types of string data.
Boolean
– это логический тип данных, который может принимать значения true (истина) или false (ложь).
A Boolean
is a true
or false
value.
ID
– это уникальный идентификатор. Этот тип данных всегда сериализуется как строка, даже если ID
числовой. Тип ID
часто представляется как Универсальный Уникальный Идентификатор (UUID).
Пользовательские скаляры
Помимо встроенных скаляров, ключевое слово scalar
можно использовать для определения пользовательского скаляра. Вы можете использовать пользовательские скаляры для создания типов с дополнительной проверкой на уровне сервера, таких как Date
, Time
или Url
. Вот пример определения нового типа Date
:
scalar Date
Сервер будет знать, как обрабатывать взаимодействия с этим новым типом, используя GraphQLScalarType
.
Тип Enum
Тип Enum, также известный как тип Enumerator, описывает набор возможных значений.
Используя тему API фэнтезийной игры из других учебников в серии Как управлять данными с помощью GraphQL, вы можете создать enum
для профессий персонажей игры и их видов с всеми значениями, которые система будет принимать для них. Перечисление определяется с использованием ключевого слова enum
, как показано ниже:
"The job class of the character."
enum Job {
FIGHTER
WIZARD
}
"The species or ancestry of the character."
enum Species {
HUMAN
ELF
DWARF
}
Таким образом, гарантируется, что Job
персонажа является FIGHTER
или WIZARD
и никогда случайно не будет "фиолетовым"
или какой-то другой случайной строкой, что могло бы быть возможно, если бы вы использовали тип String
, а не создали пользовательское перечисление. Перечисления по соглашению записываются заглавными буквами.
Перечисления также могут использоваться в качестве принимаемых значений в аргументах. Например, вы можете создать Hand
enum
, чтобы указать, одноручное (как короткий меч) или двуручное (как тяжелый топор) оружие, и использовать это для определения, можно ли экипировать одно или два:
enum Hand {
SINGLE
DOUBLE
}
"A valiant weapon wielded by a fighter."
type Weapon {
name: String!
attack: Int
range: Int
hand: Hand
}
type Query {
weapons(hand: Hand = SINGLE): [Weapon]
}
Перечисление Hand
объявлено с значениями SINGLE
и DOUBLE
, и аргумент в поле weapons
имеет значение по умолчанию SINGLE
, что означает, что если аргумент не передан, то будет использоваться значение SINGLE
.
Ненулевой тип
Вы можете заметить, что null
или undefined
, общий тип, который многие языки считают примитивным, отсутствует в списке встроенных скаляров. Null существует в GraphQL и представляет отсутствие значения.
Все типы в GraphQL по умолчанию могут быть пустыми, и, следовательно, null
является допустимым значением для любого типа. Чтобы сделать значение обязательным, его необходимо преобразовать в тип GraphQL Non-Null с восклицательным знаком в конце. Non-Null определяется как модификатор типа, который используется для модификации типа, на который он ссылается. Например, String
– это необязательная (или пустая) строка, а String!
– обязательная (или Non-Null) строка.
Тип списка
A List type in GraphQL is another type modifier. Any type that is wrapped in square brackets ([]
) becomes a List type, which is a collection that defines the type of each item in a list.
Например, тип, определенный как [Int]
, будет коллекцией типов Int
, а [String]
будет коллекцией типов String
. Non-Null и List могут быть использованы вместе, чтобы сделать тип как обязательным, так и определенным как список, например, [String]!
.
Тип объекта
Если скалярные типы GraphQL описывают “листья” в конечном иерархическом ответе GraphQL, то типы Object описывают промежуточные “ветви”, и практически все в схеме GraphQL является типом объекта.
Объекты состоят из списка именованных полей (ключей) и типа значения, к которому будет приведено каждое поле. Объекты определяются с помощью ключевого слова type
. Должно быть определено как минимум одно или более полей, причем поля не могут начинаться с двух подчеркиваний (__
), чтобы избежать конфликта с системой интроспекции GraphQL.
В примере API игры “GraphQL Fantasy Game” вы можете создать объект Fighter
, чтобы представить тип персонажа в игре:
"A hero with direct combat ability and strength."
type Fighter {
id: ID!
name: String!
level: Int
active: Boolean!
}
В этом примере тип объекта Fighter
объявлен, и у него есть четыре именованных поля:
id
выдает типID
без значения.name
выдает типString
без значения.level
выдает типInt
без значения.active
выдает типBoolean
без значения.
Выше объявления вы также можете добавить комментарий, используя двойные кавычки, как в этом примере: "Герой с прямыми боевыми навыками и силой."
. Это будет отображаться как описание для типа.
В этом примере каждое поле приводится к скалярному типу, но поля объектов также могут приводиться к другим типам объектов. Например, вы можете создать тип Weapon
, и схема GraphQL может быть настроена так, чтобы поле weapon
в объекте Fighter
приводилось к объекту Weapon
:
"A valiant weapon wielded by a fighter."
type Weapon {
name: String!
attack: Int
range: Int
}
"A hero with direct combat ability and strength."
type Fighter {
id: ID!
name: String!
level: Int
active: Boolean!
weapon: Weapon
}
Объекты также могут быть вложены в поля других объектов.
Типы корневых операций
Существуют три специальных объекта, которые служат точками входа в схему GraphQL: Query, Mutation и Subscription. Они известны как типы корневых операций и следуют всем тем же правилам, что и любой другой тип объекта.
Ключевое слово schema
представляет собой точку входа в схему GraphQL. Ваши типы корневых запросов, мутаций и подписок будут находиться в корневом объекте schema
:
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
Тип Query обязателен в любой схеме GraphQL и представляет запрос на чтение, аналогичный запросу GET
в REST API. Ниже приведен пример корневого объекта Query
, который возвращает список типов Fighter
:
type Query {
fighters: [Fighter]
}
Мутации представляют запрос на запись, который был бы аналогичен запросам POST
, PUT
или DELETE
в REST API. В следующем примере у Mutation
есть поле addFighter
с именованным аргументом (input
):
type Mutation {
addFighter(input: FighterInput): Fighter
}
Наконец, подписка соответствует потоку событий, который можно использовать с WebSocket в веб-приложении. В GraphQL Fantasy API, возможно, она могла бы использоваться для случайных боевых столкновений, как в следующем примере:
type Subscription {
randomBattle(enemy: Enemy): BattleResult
}
Обратите внимание, что точка входа schema
часто абстрагируется в некоторых реализациях GraphQL.
Поле Аргументы
Поля объекта GraphQL по сути являются функциями, которые возвращают значение, и они могут принимать аргументы, как любая функция. Аргументы поля определяются именем аргумента, за которым следует тип. Аргументы могут быть любого типа, кроме типа Object. В этом примере объект Fighter
может быть отфильтрован по полю id
(которое разрешается в тип Non-Null ID
):
type Query {
fighter(id: ID!): Fighter
}
Этот конкретный пример полезен для извлечения одного элемента из хранилища данных, но аргументы также могут использоваться для фильтрации, пагинации и других более конкретных запросов.
Тип Интерфейса
Как и тип Object, абстрактный Тип Интерфейса состоит из списка именованных полей и их ассоциированных типов значений. Интерфейсы выглядят как и следуют всем тем же правилам, что и Объекты, но они используются для определения подмножества реализации Объекта.
На данный момент в вашей схеме у вас есть объект Fighter
, но вам также может понадобиться создать объекты Wizard
, Healer
и другие объекты, которые будут иметь много общих полей, но будут иметь некоторые различия. В этом случае вы можете использовать интерфейс для определения общих для всех полей и создавать объекты, которые являются реализациями интерфейса.
В следующем примере вы можете создать интерфейс BaseCharacter
, используя ключевое слово interface
со всеми полями, которыми будет обладать каждый тип персонажа:
"A hero on a quest."
interface BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job
}
У каждого типа персонажа будут поля id
, name
, level
, species
и job
.
Теперь представьте, что у вас есть тип Fighter
и тип Wizard
, которые имеют эти общие поля, но Fighters
используют Weapon
, а Wizards
используют Spells
. Вы можете использовать ключевое слово implements
, чтобы определить каждый из них как реализацию BaseCharacter
, что означает, что у них должны быть все поля из созданного интерфейса:
"A hero with direct combat ability and strength."
type Fighter implements BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job!
weapon: Weapon
}
"A hero with a variety of magical powers."
type Wizard implements BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job!
spells: [Spell]
}
Fighter
и Wizard
являются допустимыми реализациями интерфейса BaseCharacter
, потому что они имеют требуемый поднабор полей.
Объединенный тип
Another abstract type that can be used with Objects is the Тип объединения. Используя ключевое слово union
, вы можете определить тип с перечнем объектов, которые все допустимы в качестве ответов.
Используя интерфейсы, созданные в предыдущем разделе, вы можете создать объединение Character
, определяющее персонажа как Wizard
ИЛИ Fighter
:
union Character = Wizard | Fighter
Знак равенства (=
) задает определение, а вертикальная черта (|
) функционирует как оператор OR
. Обратите внимание, что объединение должно состоять из объектов или интерфейсов. Скалярные типы не допускаются в объединении.
Теперь, если вы запрашиваете список персонажей, он может использовать объединение Character
и возвращать все типы Wizard
и Fighter
.
Заключение
В этом учебнике вы узнали о многих типах, которые определяют систему типов GraphQL. Самые фундаментальные типы – это скалярные типы, которые являются значениями, действующими как листья в дереве схемы, и состоят из Int
, Float
, String
, Boolean
, ID
и любого пользовательского скаляра, который реализация GraphQL решает создать. Перечисления – это списки допустимых константных значений, которые могут использоваться, когда вам нужно больше контроля над ответом, чем просто объявление его как String
, и они также являются листьями в дереве схемы. Типы List и Non-Null известны как модификаторы типа, или обертывающие типы, и они могут определять другие типы как коллекции или обязательные, соответственно. Объекты – это ветви дерева схемы, и почти все в схеме GraphQL является типом Object, включая точки входа query
, mutation
и subscription
. Типы Interface и Union – это абстрактные типы, которые могут быть полезны при определении объектов.
Для дальнейшего изучения вы можете практиковаться в создании и изменении схемы GraphQL, прочитав учебник Как настроить сервер API GraphQL в Node.js, чтобы иметь рабочую среду сервера GraphQL.
Source:
https://www.digitalocean.com/community/conceptual-articles/understanding-the-graphql-type-system