GraphQLの入力タイプのポイントは何ですか?


83

ミューテーションの入力引数がオブジェクトの場合、入力型にする必要がある理由を説明してください。IDを指定せずにタイプを再利用する方がはるかに簡単だと思います。

例えば:

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以上のプロパティを持つオブジェクトがたくさんある場合は、負担になります。


30
入力オブジェクトはシリアル化可能である必要があります。出力オブジェクトにはサイクルを含めることができるため、入力に再利用することはできません。
ジェシーブキャナン

1
ジェシー、それは十分な答えのように見えます!あなたは答えることができます、そして私はそれをそうマークします。
Dmitry Dushkin 2017年

インターフェイスをそれと組み合わせることが可能か
どうか疑問に思う

回答:


99

仕様から:

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サービスによって生成された応答の一部として返される可能性のあるタイプです。入力タイプは、フィールドまたはディレクティブ引数の有効な入力であるタイプです。

これらの2つのグループ(つまり、スカラー、列挙型、リスト、および非ヌル)の間には重複があります。ただし、ユニオンやインターフェイスなどの抽象型は、入力コンテキストでは意味がなく、入力として使用することはできません。オブジェクト型と入力オブジェクト型を分離することで、入力型が期待される場所で抽象型が使用されないようにすることができます。

スキーマ設計

スキーマでエンティティを表す場合、一部のエンティティは実際にそれぞれの入力タイプと出力タイプの間で「フィールドを共有」する可能性があります。

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
}

これらの構造適切な入力に変換される場合がありますが(Studentを作成するため、アドレスを表すオブジェクトも渡します)、多くの場合、そうではありません。つまり、学生のクラスをクラスIDとセクションIDで指定する必要があります。オブジェクト。同様に、返したいが変更したくないpasswordフィールドがある場合や、その逆の場合もあります(フィールドのように)。

さらに、比較的単純なエンティティの場合でも、オブジェクトタイプとその「対応する」入力オブジェクトの間でnull可能性に関する要件が異なることがよくあります。多くの場合、フィールドが応答でも返されることを保証したいのですが、入力で必要とされるのと同じフィールドを作成したくありません。例えば、

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

input StudentInput {
  firstName: String
  lastName: String
}

最後に、多くのスキーマでは、特定のエンティティのオブジェクトタイプと入力オブジェクトタイプの間に1対1のマッピングがないことがよくあります。一般的なパターンは、スキーマレベルの入力検証をさらに微調整するために、さまざまな操作に個別の入力オブジェクトタイプを利用することです。

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

input UpdateUserInput {
  email: String
  password: String
}

これらの例はすべて重要なポイントを示しています。入力オブジェクトタイプはオブジェクトタイプを反映している場合がありますが、ビジネス要件のために本番スキーマでそれを確認する可能性ははるかに低くなります。


4
これは確かに素晴らしい答えです!
チャーリーン

私が間違っている場合は訂正してください。しかし、あなたの例では、タイプGradeを入力StudentInputで再利用することはできませんよね?入力オブジェクトのフィールドをインライン化するか、入力オブジェクトを用意する必要がありGradeInputます。
マット

2
@マット良い質問です!上記の例でGradeは、は列挙型です。オブジェクトとは異なり、スカラー型(String、Intなど)と列挙型は入力型出力型の両方として使用できます。
ダニエルリアデン

いい説明
Visakh Vijayan

確かに素晴らしい答えです!
ジョニー

25

ジェシーのコメントは正しいです。より正式な答えについては、入力タイプに関するGraphQLドキュメントからの抜粋を次に示します

上記で定義されたオブジェクトタイプは、ここでの再利用には不適切です。オブジェクトには、循環参照またはインターフェイスと共用体への参照を表すフィールドが含まれている可能性があり、どちらも入力引数としての使用には適していません。このため、入力オブジェクトはシステム内で別のタイプになります。

更新

それを投稿してから、循環参照は、それらがゼロである限り(そうでなければ、無限のチェーンを宣言する)、実際に受け入れられることがわかりました。しかし、それでも、入力用に別の型システムを必要とするように思われる他の制限(インターフェースなど)があります。


4
この制限が存在する理由については、もう少し議論があります:github.com/graphql/graphql-js/issues/599
Cam Jackson
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.