diff --git a/.prettierignore b/.prettierignore index e3f467af83..3597d1ddef 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,6 +5,7 @@ pnpm-lock.yaml !src/pages/blog/2024-08-15-graphql-local-initiative.mdx !src/pages/community/foundation/community-grant.mdx !src/pages/blog/2025-06-01-graphiql-4/index.mdx +!src/pages/blog/2025-06-19-multioption-inputs-with-oneof/index.mdx *.jpg scripts/sync-sched/*.json diff --git a/src/pages/blog/2025-06-19-multioption-inputs-with-oneof/index.mdx b/src/pages/blog/2025-06-19-multioption-inputs-with-oneof/index.mdx new file mode 100644 index 0000000000..efab118e26 --- /dev/null +++ b/src/pages/blog/2025-06-19-multioption-inputs-with-oneof/index.mdx @@ -0,0 +1,142 @@ +--- +title: Safer Multi-option Inputs with `@oneOf` +tags: [announcements, spec] +date: 2025-06-19 +byline: Benjie Gillam +--- + +We’re excited to announce +**[OneOf Input Objects](https://github.com/graphql/graphql-spec/pull/825)** 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: + +```graphql +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: + +```graphql +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: + +```graphql +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 + +You might wonder why this is expressed as a directive in SDL rather than +explicitly having a new type keyword; Brad Baker, contributor to GraphQL-Java, +summed it up in [this comment back in +2023](https://github.com/graphql/graphql-spec/pull/825#issuecomment-1659900665): + +> use of the directive means that: +> +> - it's minimally invasive in terms of SDL tooling that might be out there, +> - it's minimally invasive in terms of Introspection, +> - it's minimally invasive in terms of engine implementation, it proved quite easy to implement in graphql-java. +> +> Great stuff! + +Since then there have been a number of reports of success: + +> I'm very happy with where this landed. We'd use it internally at my company. -- [Ethan Resnick](https://github.com/graphql/graphql-spec/pull/825#issuecomment-2128262620) + +> More positive feedback: We are using it at HubSpot through the graphql-java implementation and look forward to it becoming standardized. -- [Henry Q. Dineen](https://github.com/graphql/graphql-spec/pull/825#issuecomment-2128324080) + +> I implemented support for OneOf input objects for the Caliban GraphQL library (Scala) [...] it's been fairly straightforward implementing support for it and I couldn't really identify any areas that could have been improved. -- [kyri-petrou](https://github.com/kyri-petrou) + +> We have been eagerly waiting at Jobber for this to land as well. [...] We have many use cases internally for it and we're very excited to see this land! -- [Clinton Pahl](https://github.com/graphql/graphql-spec/pull/825#issuecomment-2135724148) + +> Colleagues at work (Atlassian) have been really happy with @oneOf, works exactly as you want it to and I haven't heard any negative feedback. -- [Donna Zhou](https://github.com/dondonz) + +## Availability + +`@oneOf` is already available in the following implementations of GraphQL: + +- GraphQL.js v16+ +- GraphQL Ruby v2.0.21+ +- GraphQL.NET v8+ +- GraphQL Java v21.2+ +- HotChocolate v16.0.0+ +- Probably others! + +## 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!