From 6503fd62bac6a9937bc961fae35e40e9cfdbad0b Mon Sep 17 00:00:00 2001 From: jdecroock Date: Thu, 7 Nov 2024 20:52:24 +0100 Subject: [PATCH 1/2] Write about input unions --- website/pages/_meta.ts | 1 + website/pages/input-unions.mdx | 72 ++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 website/pages/input-unions.mdx diff --git a/website/pages/_meta.ts b/website/pages/_meta.ts index 0164d2ec1e..baa9f41c71 100644 --- a/website/pages/_meta.ts +++ b/website/pages/_meta.ts @@ -17,6 +17,7 @@ const meta = { title: 'Advanced Guides', }, 'constructing-types': '', + 'input-unions': '', 'defer-stream': '', '-- 3': { type: 'separator', diff --git a/website/pages/input-unions.mdx b/website/pages/input-unions.mdx new file mode 100644 index 0000000000..718c253077 --- /dev/null +++ b/website/pages/input-unions.mdx @@ -0,0 +1,72 @@ +--- +title: Input Unions +--- + +import { Tabs } from 'nextra/components'; + +Some inputs will behave differently depending on what input we choose. Let's look at the case for +a field named `product`, we can fetch a `Product` by either its `id` or its `name`. Currently we'd +make a tradeoff for this by introducing two arguments that are both nullable, now if both are passed +as null we'd have to handle that in code. To fix this the `@oneOf` directive was introduced so we +can create these input-unions without sacrificing the strictly typed nature of our GraphQL Schema. + + + +```js +const schema = buildSchema(` + type Product { + id: ID! + name: String! + } + + input ProductInput @oneOf { + id: ID + name: String + } + + type Query { + product(input: ProductInput!): Product + } +`); +``` + + +```js +const Product = new GraphQLObjectType({ + name: 'Product', + fields: { + id: { + type: new GraphQLNonNull(GraphQLID), + }, + name: { + type: new GraphQLNonNull(GraphQLString), + }, + }, +}); + +const ProductInput = new GraphQLInputObjectType({ + name: 'ProductInput', + isOneOf: true, + fields: { + id: { type: GraphQLID }, + name: { type: GraphQLString }, + }, +}); + +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + product: { + type: Product, + args: { input: { type: ProductInput } }, + }, + }, + }), +}); +``` + + + +It doesn't matter whether you have 2 or more inputs here, all that matters is +that your user will have to specify one, and only one, for this input to be valid. \ No newline at end of file From 34a6ed7773dcf1c713b03789f8487fa3154db3ea Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Fri, 8 Nov 2024 14:27:13 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Benjie --- cspell.yml | 1 + website/pages/_meta.ts | 2 +- ...put-unions.mdx => oneof-input-objects.mdx} | 37 ++++++++++++++----- 3 files changed, 30 insertions(+), 10 deletions(-) rename website/pages/{input-unions.mdx => oneof-input-objects.mdx} (53%) diff --git a/cspell.yml b/cspell.yml index 1e6bb26c3d..ff26b0902b 100644 --- a/cspell.yml +++ b/cspell.yml @@ -59,6 +59,7 @@ words: - tailwindcss - svgr - ruru + - oneof # used as href anchors - graphqlerror diff --git a/website/pages/_meta.ts b/website/pages/_meta.ts index baa9f41c71..7b0f42dca3 100644 --- a/website/pages/_meta.ts +++ b/website/pages/_meta.ts @@ -17,7 +17,7 @@ const meta = { title: 'Advanced Guides', }, 'constructing-types': '', - 'input-unions': '', + 'oneof-input-objects': 'OneOf input objects', 'defer-stream': '', '-- 3': { type: 'separator', diff --git a/website/pages/input-unions.mdx b/website/pages/oneof-input-objects.mdx similarity index 53% rename from website/pages/input-unions.mdx rename to website/pages/oneof-input-objects.mdx index 718c253077..95be65d2c2 100644 --- a/website/pages/input-unions.mdx +++ b/website/pages/oneof-input-objects.mdx @@ -1,5 +1,5 @@ --- -title: Input Unions +title: OneOf input objects --- import { Tabs } from 'nextra/components'; @@ -7,8 +7,8 @@ import { Tabs } from 'nextra/components'; Some inputs will behave differently depending on what input we choose. Let's look at the case for a field named `product`, we can fetch a `Product` by either its `id` or its `name`. Currently we'd make a tradeoff for this by introducing two arguments that are both nullable, now if both are passed -as null we'd have to handle that in code. To fix this the `@oneOf` directive was introduced so we -can create these input-unions without sacrificing the strictly typed nature of our GraphQL Schema. +as null (or both non-null) we'd have to handle that in code - the type system wouldn't indicate that exactly one was required. To fix this, the `@oneOf` directive was introduced so we +can create this "exactly one option" constraint without sacrificing the strictly typed nature of our GraphQL Schema. @@ -19,13 +19,20 @@ const schema = buildSchema(` name: String! } - input ProductInput @oneOf { + input ProductLocation { + aisleNumber: Int! + shelfNumber: Int! + positionOnShelf: Int! + } + + input ProductSpecifier @oneOf { id: ID name: String + location: ProductLocation } type Query { - product(input: ProductInput!): Product + product(by: ProductSpecifier!): Product } `); ``` @@ -44,12 +51,23 @@ const Product = new GraphQLObjectType({ }, }); -const ProductInput = new GraphQLInputObjectType({ - name: 'ProductInput', +const ProductLocation = new GraphQLInputObjectType({ + name: 'ProductLocation', + isOneOf: true, + fields: { + aisleNumber: { type: GraphQLInt }, + shelfNumber: { type: GraphQLInt }, + positionOnShelf: { type: GraphQLInt }, + }, +}); + +const ProductSpecifier = new GraphQLInputObjectType({ + name: 'ProductSpecifier', isOneOf: true, fields: { id: { type: GraphQLID }, name: { type: GraphQLString }, + location: { type: ProductLocation }, }, }); @@ -59,7 +77,7 @@ const schema = new GraphQLSchema({ fields: { product: { type: Product, - args: { input: { type: ProductInput } }, + args: { by: { type: ProductSpecifier } }, }, }, }), @@ -69,4 +87,5 @@ const schema = new GraphQLSchema({ It doesn't matter whether you have 2 or more inputs here, all that matters is -that your user will have to specify one, and only one, for this input to be valid. \ No newline at end of file +that your user will have to specify one, and only one, for this input to be valid. +The values are not limited to scalars, lists and other input object types are also allowed. \ No newline at end of file