Aus der Spezifikation:
Der GraphQL-Objekttyp (ObjectTypeDefinition) ... ist für die Wiederverwendung [als Eingabe] ungeeignet, da Objekttypen Felder enthalten können, die Argumente definieren oder Verweise auf Schnittstellen und Vereinigungen enthalten, von denen keines als Eingabeargument geeignet ist . Aus diesem Grund haben Eingabeobjekte im System einen separaten Typ.
Das ist der "offizielle Grund", aber es gibt mehrere praktische Gründe, warum Sie einen Objekttyp nicht als Eingabeobjekttyp oder einen Objekttyp als Eingabeobjekttyp verwenden können:
Funktionalität
Objekttypen und Eingabeobjekttypen haben beide Felder. Diese Felder haben jedoch unterschiedliche Eigenschaften, die widerspiegeln, wie diese Typen vom Schema verwendet werden. Ihr Schema definiert möglicherweise Argumente und eine Art Resolverfunktion für die Felder eines Objekttyps, aber diese Eigenschaften sind in einem Eingabekontext nicht sinnvoll (dh Sie können das Feld eines Eingabeobjekts nicht auflösen - es hat bereits einen expliziten Wert). . Ebenso können Standardwerte nur für Eingabeobjekttypfelder und nicht für Objekttypfelder angegeben werden.
Mit anderen Worten, dies scheint eine Vervielfältigung zu sein:
type Student {
name: String
grade: Grade
}
input StudentInput {
name: String
grade: Grade
}
Durch Hinzufügen von Funktionen, die entweder für Objekttypen oder für Eingabeobjekttypen spezifisch sind, wird jedoch deutlich, dass sie sich unterschiedlich verhalten:
type Student {
name(preferred: Boolean): String
grade: Grade
}
input StudentInput {
name: String
grade: Grade = F
}
Geben Sie Systemeinschränkungen ein
Typen in GraphQL werden in Ausgabetypen und Eingabetypen gruppiert .
Ausgabetypen sind Typen, die als Teil einer von einem GraphQL-Dienst erzeugten Antwort zurückgegeben werden können. Eingabetypen sind Typen, die gültige Eingaben für Feld- oder Direktivenargumente sind.
Es gibt Überschneidungen zwischen diesen beiden Gruppen (dh Skalare, Aufzählungen, Listen und Nicht-Nullen). Allerdings abstrakte Typen wie Gewerkschaften und Schnittstellen keinen Sinn in einem Eingabekontext machen und können nicht als Eingänge verwendet werden. Durch die Trennung von Objekttypen und Eingabeobjekttypen können Sie sicherstellen, dass ein abstrakter Typ niemals dort verwendet wird, wo ein Eingabetyp erwartet wird.
Schemadesign
Bei der Darstellung einer Entität in Ihrem Schema ist es wahrscheinlich, dass einige Entitäten tatsächlich Felder zwischen ihren jeweiligen Eingabe- und Ausgabetypen "gemeinsam nutzen":
type Student {
firstName: String
lastName: String
grade: Grade
}
input StudentInput {
firstName: String
lastName: String
grade: Grade
}
Objekttypen können jedoch (und in der Realität häufig) sehr komplexe Datenstrukturen modellieren:
type Student {
fullName: String!
classes: [Class!]!
address: Address!
emergencyContact: Contact
# etc
}
Während diese Strukturen können in entsprechende Eingaben übersetzen (wir einen Studenten schaffen, so dass wir in einem Objekt darstellt , ihre Adresse auch passieren), oft sie es nicht tun - also vielleicht müssen wir den Schüler-Klassen von Klassen - ID und Abschnitt - ID angeben, nicht ein Objekt. In ähnlicher Weise haben wir möglicherweise Felder, die wir zurückgeben möchten, aber nicht mutieren möchten, oder umgekehrt (wie ein password
Feld).
Darüber hinaus haben wir selbst für relativ einfache Entitäten häufig unterschiedliche Anforderungen an die Nullbarkeit zwischen Objekttypen und ihren "Gegenstück" -Eingabeobjekten. Oft möchten wir sicherstellen, dass ein Feld auch in einer Antwort zurückgegeben wird, aber wir möchten nicht dieselben Felder für unsere Eingabe benötigen. Zum Beispiel,
type Student {
firstName: String!
lastName: String!
}
input StudentInput {
firstName: String
lastName: String
}
Schließlich gibt es in vielen Schemata häufig keine Eins-zu-Eins-Zuordnung zwischen Objekttyp und Eingabeobjekttyp für eine bestimmte Entität. Ein gemeinsames Muster besteht darin, separate Eingabeobjekttypen für verschiedene Operationen zu verwenden, um die Eingabevalidierung auf Schemaebene weiter zu optimieren:
input CreateUserInput {
firstName: String!
lastName: String!
email: String!
password: String!
}
input UpdateUserInput {
email: String
password: String
}
Alle diese Beispiele veranschaulichen einen wichtigen Punkt: Während ein Eingabeobjekttyp manchmal einen Objekttyp widerspiegelt, ist es aufgrund von Geschäftsanforderungen weniger wahrscheinlich, dass dies in Produktionsschemata der Fall ist.