Який сенс вводити тип в GraphQL?


90

Не могли б ви пояснити, чому якщо вхідний аргумент мутації є об'єктом, це повинен бути тип вводу ? Я думаю, що набагато простіше просто повторно використовувати тип без надання ідентифікатора.

Наприклад:

type Sample {
  id: String
  name: String
}

input SampleInput {
  name: String
}

type RootMutation {
  addSample(sample: Sample): Sample  # <-- instead of it should be
  addSample(sample: SampleInput): Sample
}

Це нормально для невеликих об’єктів, але коли у вас у схемі багато об’єктів із 10+ властивостями, це стане тягарем.


32
Вхідні об’єкти мають бути серіалізуються. Оскільки вихідні об'єкти можуть містити цикли, їх не можна використовувати повторно для введення.
Джессі Бьюкенен

1
Джессі, схоже, досить відповіді! Ви можете відповісти, і я це так позначаю.
Дмитро Душкін

Цікаво, чи можна поєднувати з ним інтерфейси
MVCDS

Відповіді:


114

З специфікації:

Тип об’єкта GraphQL (ObjectTypeDefinition) ... непридатний для повторного використання [як вхід], оскільки типи об’єктів можуть містити поля, що визначають аргументи або містять посилання на інтерфейси та об’єднання, жодне з яких не підходить для використання як аргумент введення. . З цієї причини вхідні об'єкти мають окремий тип в системі.

Це "офіційна причина", але є кілька практичних причин, чому ви не можете використовувати тип об'єкта як тип об'єкта введення або використовувати тип об'єкта як тип об'єкта введення:

Функціональність

Типи об'єктів і типи об'єктів введення мають поля, проте ці поля мають різні властивості, що відображають, як ці типи використовуються схемою. Ваша схема потенційно може визначати аргументи та якусь функцію резольвера для полів типу об'єкта, але ці властивості не мають сенсу у контексті введення (тобто ви не можете вирішити поле вхідного об'єкта - воно вже має явне значення) . Аналогічним чином, значення за замовчуванням можуть надаватися лише для полів типу вхідного об'єкта, а не поля полів типу об'єкта.

Іншими словами, це може здатися дублюванням:

type Student {
  name: String
  grade: Grade
}

input StudentInput {
  name: String
  grade: Grade
}

Але додавання особливостей, характерних для типів об’єктів або типів об’єктів введення, дає зрозуміти, що вони поводяться по-різному:

type Student {
  name(preferred: Boolean): String
  grade: Grade
}

input StudentInput {
  name: String
  grade: Grade = F
}

Обмеження системи типу

Типи в GraphQL групуються за видами виводу та типами введення .

Типи виводу - це типи, які можуть бути повернуті як частина відповіді, створеної службою GraphQL. Типи введення - це типи, які є допустимими входами для аргументів поля або директиви.

Між цими двома групами (тобто скалярами, переліками, списками та ненульовими значеннями) існує перекриття. Однак абстрактні типи, такі як об'єднання та інтерфейси, не мають сенсу у контексті введення і не можуть використовуватися як входи. Розділення типів об’єктів та типів об’єктів введення дозволяє забезпечити, щоб абстрактний тип ніколи не використовувався там, де очікується тип введення.

Схема проектування

Представляючи сутність у вашій схемі, цілком ймовірно, що деякі сутності дійсно будуть «ділити поля» між відповідними типами вводу та виводу:

type Student {
  firstName: String
  lastName: String
  grade: Grade
}

input StudentInput {
  firstName: String
  lastName: String
  grade: Grade
}

Однак типи об’єктів можуть (а насправді це часто роблять) моделювати дуже складні структури даних:

type Student {
  fullName: String!
  classes: [Class!]!
  address: Address!
  emergencyContact: Contact
  # etc
}

Хоча ці структури можуть транслюватись у відповідні вхідні дані (ми створюємо студента, тому ми також передаємо об'єкт, що представляє їх адресу), часто вони цього не роблять - тобто, можливо, нам потрібно вказати класи студента за ідентифікатором класу та ідентифікатором розділу, а не за об'єкт. Так само ми можемо мати поля, які ми хочемо повернути, але не хочемо мутувати, або навпаки (як passwordполе).

Більше того, навіть щодо відносно простих сутностей ми часто маємо різні вимоги щодо дозволеності між типами об'єктів та об'єктами вводу "відповідних". Часто ми хочемо гарантувати, що поле також буде повернуто у відповідь, але ми не хочемо вводити ті самі поля, які вимагаються в нашому введенні. Наприклад,

type Student {
  firstName: String!
  lastName: String!
}

input StudentInput {
  firstName: String
  lastName: String
}

Нарешті, у багатьох схемах часто не існує однозначного зіставлення між типом об’єкта та типом об’єкта введення для даної сутності. Загальним шаблоном є використання окремих типів об’єктів введення для різних операцій для подальшої точної настройки перевірки введення на рівні схеми:

input CreateUserInput {
  firstName: String!
  lastName: String!
  email: String!
  password: String!
}

input UpdateUserInput {
  email: String
  password: String
}

Всі ці приклади ілюструють важливий момент - хоча вхідний тип об'єкта може часом відображати тип об'єкта, ви набагато рідше бачите це у виробничих схемах через бізнес-вимоги.


4
це справді чудова відповідь!
Charlie Ng

Виправте мене, якщо я помиляюся, але у вашому прикладі тип Gradeне можна використовувати повторно у введенні StudentInput, так? Вам потрібно буде вставити вбудовані поля у об’єкт введення або мати об’єкт GradeInputвведення.
Метт,

2
@Matt Гарне запитання! У наведеному вище прикладі Gradeце тип переліку. В відміну від об'єктів, скалярні типи (наприклад , String, Int і т.д.) і перерахувань типів можуть бути використані в якості обох типів вхідних і вихідних типів.
Даніель Ріарден,

гарне пояснення
Вісах Віджаян

Насправді чудова відповідь!
Джонні

25

Коментар Джессі правильний. Для отримання більш офіційної відповіді, ось витяг з документації GraphQL про типи введення :

Визначений вище тип Об'єкта тут не підходить для повторного використання, оскільки Об'єкти можуть містити поля, що виражають кругові посилання або посилання на інтерфейси та об'єднання, жодне з яких не підходить для використання як вхідний аргумент. З цієї причини вхідні об'єкти мають окремий тип в системі.

ОНОВЛЕННЯ

Опублікувавши його, я виявив, що циркулярні посилання насправді є прийнятними, якщо їх можна відмінити (інакше це оголосить нескінченний ланцюг). Але все-таки існують інші обмеження (наприклад, інтерфейси), які, здається, потребують окремої системи типу для входів.


4
Тут трохи більше обговорюється, чому існує це обмеження: github.com/graphql/graphql-js/issues/599
Кем Джексон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.