З специфікації:
Тип об’єкта 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
}
Всі ці приклади ілюструють важливий момент - хоча вхідний тип об'єкта може часом відображати тип об'єкта, ви набагато рідше бачите це у виробничих схемах через бізнес-вимоги.