-
Notifications
You must be signed in to change notification settings - Fork 123
Description
The problem
Tracking whether removing fields used by input types is tricky.
Today, treating all fields reachable from within an input type as being "in use" is the safest bet. However, this does not make it easy to systematically deprecated and remove these fields.
Today, as an additional feature, we allow a usage reporting for analysing the input variables and reporting input usage based on this. Also this approach is not 100% safe, as e.g. a nullable field not being used today could be a coincidence as it is a value that is rarely provided by a client.
Thus these options cannot guarantee hazzle-free (conditional) breaking changes.
Idea for an alternative way to track input usage
What if the clients define what input types they use for their GraphQL operation? This could be an annotation on the GraphQL operation variables definition and tools like GraphQL Code Generator or Relay could compliment the DX by only generating variable types based on that constraint definition.
Example GraphQL Schema:
enum ProjectType {
FEDERATION
MONOLITH
STITCHING
}
type ProjectSettingsInput {
compositionUrl: String
someOtherSetting: String
}
input CreateProjectInput {
type: ProjectType!
slug: String!
settings: ProjectSettingsInput
}
type Mutation {
createProject(input: CreateProjectInput!): Boolean
}Example GraphQL Operation:
mutation CreateProject(
$input: CreateProjectInput!
@constraints(selectionSet:
"""
{
type @constraints(enumValues: [ProjectType.Federation, ProjectType.STITCHING])
slug
settings {
compositionUrl
}
}
"""
)
) {
createProject(input: $input)
}The @constraints directive would be used on input types for defining the contract of the input type for this operation type. The argument @constraints(selectionSet:), would be a multi-line string that specifies the (deep) selection set being used within the input type.
In addition to that @constraints(enumValues:) can also be used to restrict enum input values.
Based on the above operation, the GraphQL API could remove ProjectType.MONOLITH and ProjectSettingsInput.someOtherSetting, without the client being affected.
Input constraint usage implications:
-
The GraphQL would raise an error if the above operation is executed with either
ProjectType.MONOLITHorProjectSettingsInput.someOtherSettingwithin the variable values, based on the defined contract. -
GraphQL Code Generator would generate the variable definitions for the mutation with the contraints in mind:
type CreateProjectVariables = { type: "FEDERATION" | "STITCHING"; slug: string; settings: { compositionUrl: string } | null }
-
The Hive Router/SDK reporting could report the usage to the registry based on the specified constraint.
-
The registry can provide conditional breaking changes based on the constrained usage reporting/ app deployemt operation sets
How would the deprecation/removal process for a field look like
Based on the above operation and schema, let's say we want to remove ProjectSettingsInput.settings. As usual we would first mark it as deprecated. As soon as the field is marked as deprecated, client consumers using that field would be informed (based on alert configuration etc.). They can then update their operation input contract to remove that field usage.
mutation CreateProject(
$input: CreateProjectInput!
@constraints(selectionSet:
"""
{
type @constraints(enumValues: [ProjectType.Federation, ProjectType.STITCHING])
slug
- settings {
- compositionUrl
- }
}
"""
)
) {
createProject(input: $input)
}Once the client usage is in production and the contract definition is reflected in the usage of the schema, the field ProjectSettingsInput.settings is then safe to be removed.