Opt-in features
At a glance
- Identifier: OptInFeatures
- Stage: RFC0: Strawman
- Champion: -
- PR: -
Timeline
- RFC document updated on 2022-09-30 by Martin Bonnin
- RFC document updated on 2022-06-07 by Martin Bonnin
- RFC document created on 2022-06-06 by Martin Bonnin
RFC: Opt-in features
Proposed by: Martin Bonnin
This document is a work in progress. A lot of the questions about introspection are closely related to #300 (
Expose user-defined meta-information via introspection API in form of directives
) and will therefore need to be revisited based on the progress there.📜 Problem Statement
GraphQL has a built-in mechanism for deprecation allowing to gracefully remove features from the schema. The lifecycle of a feature can typically be represented as
stable
->deprecated
->removed
.In a lot of cases though, a feature lifecycle includes an experimental phase where it has just been added and can be changed without warning. In this state, the feature is usable and feedback is encouraged but isn't considered stable enough to be put in production. The feature lifecycle becomes
experimental
->stable
->deprecated
->removed
.Goals
The goal of this proposal is to support the
experimental
state and, moving forward, any state that requires the client developer to make an explicit decision before using a given feature. In that sense, it's about "opting in" to using the feature, which includes supportingexperimental
states.To give a few examples:
a field is experimental and might be changed or removed without prior notice (the above example).
a field is expensive to compute and should be used with caution.
a field has specific security requirements and requires a specific header or other form of authentication.
Non-goals
This proposal is not about security and/or hiding parts of a schema. Its goal is to make it easier to communicate opt-in features to client developer and therefore needs to expose that information.
👀 Prior work
- GitHub uses schema previews to opt-in new features.
- Kotlin has OptIn requirements that started out as
@Experimental
before being changed to@RequiresOptIn
- Atlassian has a
@beta
directive that is enforced during execution. A client must provide aX-ExperimentalApi: $Feature
HTTP header or the request will fail.- Midas uses a
hiddenIn
directive.🧑💻 Proposed solution
The
@requiresOptIn
directiveIt is proposed to add an
@requiresOptIn
directive to the specification:"""
Indicates that the given field, argument, input field or enum value requires
giving explicit consent before being used.
"""
directive @requiresOptIn(feature: String!) repeatable
on FIELD_DEFINITION
| ARGUMENT_DEFINITION
| INPUT_FIELD_DEFINITION
| ENUM_VALUEThe
optIn
directive can then be used in the schema. For an example, to signal an experimental field:type Session {
id: ID!
title: String!
# [...]
startInstant: Instant @requiresOptIn(feature: "experimentalInstantApi")
endInstant: Instant @requiresOptIn(feature: "experimentalInstantApi")
}Introspection
This section is a proposal based on the current introspection mechanism. A more global mechanism ( see #300) would make it obsolete
@requiresOptIn
features should be hidden from introspection by default and include ifincludeRequiresOptIn
contains the given feature:type __Type {
kind: __TypeKind!
name: String
# [...] other fields omitted for clarity
# includeRequiresOptIn is a list of features to include
fields(includeDeprecated: Boolean = false, includeRequiresOptIn: [String!]): [__Field!]
}Tools can get a list of
@requiresOptIn
features required to use a field (or input field, argument, enum value) usingrequiresOptIn
:type __Field {
name: String!
isDeprecated: Boolean!
# [...] other fields omitted for clarity
# list of @requiresOptIn features required to use this field
requiresOptIn: [String!]
args(includeDeprecated: Boolean = false, includeRequiresOptIn: [String!]): [__InputValue!]!
}A given field is included in introspection results if all the conditions are satisfied. In pseudo code, if the following condition is true:
includeRequiresOptIn.containsAll(field.requiresOptIn) && (includeDeprecated || !field.isDeprecated)
Validation