Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions website/pages/_meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const meta = {
title: 'Advanced Guides',
},
'constructing-types': '',
'input-unions': '',
'defer-stream': '',
'-- 3': {
type: 'separator',
Expand Down
72 changes: 72 additions & 0 deletions website/pages/input-unions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Input Unions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oneOf is not equivalent to "input union". You can use it to form an input union, but its use is broader than that. I would title it "OneOf input objects" or similar.

(Example: input UserSpecifier @oneOf { databaseId: Int, username: String, hospitalNumber: Int } - note that both databaseId and hospitalNumber are Int and can uniquely identify a user in different ways - so this isn't simply a union.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My hesitancy was mainly that it's less of a clickthrough as the name is opaque to people while a general known word helps. I do agree that they are not the same

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree; perhaps the URL would be oneof and the title would be "OneOf and input unions" or similar?

---

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.

<Tabs items={['SDL', 'Code']}>
<Tabs.Tab>
```js
const schema = buildSchema(`
type Product {
id: ID!
name: String!
}

input ProductInput @oneOf {
id: ID
name: String
}

type Query {
product(input: ProductInput!): Product
}
`);
```
</Tabs.Tab>
<Tabs.Tab>
```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 } },
},
},
}),
});
```
</Tabs.Tab>
</Tabs>

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.
Loading