Safer Multi-option Inputs with `@oneOf`
We’re excited to announce OneOf Input Objects has landed in the GraphQL specification! This enhancement solves a long-standing challenge in API design: how to allow users to provide exactly one of several possible options as input, in a clean and enforceable way. This feature is a small change that packs a big return for developers building modern digital products with GraphQL.
Simplifying entrypoints
Most GraphQL queries start at a single node, and traverse the data graph from there. But often, there is more than one way of locating that node; for example you might find a user by their ID, email address, or username. Traditionally, that meant multiple root-level fields:
type Query {
user(id: ID!): User
userByEmail(email: String!): User
userByUsername(username: String!): User
}
(An alternative approach was a less-than-type-safe field presenting all the options along with custom runtime validation to enforce the constraints. Either way, neither solution was ideal.)
With @oneOf
, you can now consolidate those options into a single,
user-friendly input which ensures users supply exactly one input field, the
value of which must not be null. The result: a user-friendly schema with fewer
root-level fields and without sacrificing type safety:
input UserBy @oneOf {
id: ID
email: String
username: String
}
type Query {
user(by: UserBy!): User
}
Input polymorphism
Of course, @oneOf
’s use isn’t limited to simple scalars — it can also be used
to choose between multiple complex input types, allowing for polymorphism in
GraphQL inputs.
Imagine you were building a user-friendly blogging website, and each post is made up of elements — paragraphs, image galleries, block quotes, code blocks, and the like. Each of these elements come with their own set of (potentially overlapping) attributes, and you want to feed a list of them into your mutation. With @oneOf you can do so in a type safe manner:
type Mutation {
createPost(elements: [PostElementInput]): Post
}
input PostElementInput @oneOf {
paragraph: ParagraphInput
blockquote: BlockQuoteInput
gallery: GalleryInput
}
input ParagraphInput {
text: String!
}
input BlockQuoteInput {
text: String!
attribution: String
attributionUrl: String
}
input GalleryInput {
imageUrls: [String!]!
caption: String
attribution: String
}
What Makes @oneOf
The Right Solution?
- Backward Compatible: Existing tools, queries and clients still work, meaning no major overhauls are required. Existing clients can even use oneOf inputs without updating; just be careful to always supply exactly one value!
- Minimal Complexity: This feature introduces only a small change to the existing type system, but delivers very significant benefits.
- Type-Safe Input Polymorphism: Offers a safe and scalable way to accept a variety of inputs under a single structure—something previously hard to achieve in GraphQL.
- Now part of the GraphQL standard: Several GraphQL implementations
including Ruby, Java, JavaScript and .NET already ship
@oneOf
as a stable feature
The Bottom Line
@oneOf
allows for more expressive, capable, and less overwhelming schemas,
helping technical teams to move faster with increased safety. It’s simple and
easy to implement, try it today!