Created
February 5, 2025 13:38
-
-
Save rmosolgo/f4201e8dd94ebe9f84881b523df1602a to your computer and use it in GitHub Desktop.
Assigning a GraphQL-Ruby changeset version from a directive in the query
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "bundler/inline" | |
gemfile do | |
gem "graphql", "2.4.8", source: "https://rubygems.org" | |
gem "graphql-enterprise", source: "https://gems.graphql.pro" | |
end | |
class MySchema < GraphQL::Schema | |
class SwitchFields < GraphQL::Enterprise::Changeset | |
release "2025-02-01" | |
end | |
class BaseField < GraphQL::Schema::Field | |
include GraphQL::Enterprise::Changeset::FieldIntegration | |
end | |
class Query < GraphQL::Schema::Object | |
field_class BaseField | |
field :old_field, String, fallback_value: "Old", removed_in: SwitchFields | |
field :new_field, String, fallback_value: "New", added_in: SwitchFields | |
end | |
# This directive definition is used for validation. | |
class Changeset < GraphQL::Schema::Directive | |
locations(QUERY, SUBSCRIPTION, MUTATION) | |
argument :version, String | |
end | |
# This trace module will read the value from the query AST | |
# and apply it to the `query.context` Hash. | |
# | |
# (Directive classes have a `.resolve` method, but it's too late for this | |
# application because it's called during execution, but we need this | |
# key to be present in context during _validation_.) | |
# | |
# `execute_multiplex` is the top-level hook, so we can do it there. | |
module SetChangesetFromDirective | |
def execute_multiplex(multiplex:) | |
multiplex.queries.each do |query| | |
operation = query.selected_operation | |
if (dir = operation.directives.find { |d| d.name == "changeset" }) | |
changeset_version = dir.arguments.first.value | |
query.context[:changeset_version] = changeset_version | |
end | |
end | |
super | |
end | |
end | |
query(Query) | |
directive(Changeset) | |
trace_with(SetChangesetFromDirective) | |
use GraphQL::Schema::Visibility | |
use GraphQL::Enterprise::Changeset::Release, changesets: [SwitchFields] | |
end | |
# Using context: | |
pp MySchema.execute("{ newField }", context: { changeset_version: "2025-02-01" }).to_h | |
# {"data" => {"newField" => "New"}} | |
pp MySchema.execute("{ oldField }", context: { changeset_version: "2025-02-01" }).to_h | |
# {"errors" => [{"message" => "Field 'oldField' doesn't exist on type 'Query'", "locations" => [{"line" => 1, "column" => 3}], "path" => ["query", "oldField"], "extensions" => {"code" => "undefinedField", "typeName" => "Query", "fieldName" => "oldField"}}]} | |
pp MySchema.execute("{ oldField }", context: { changeset_version: "2024-02-01" }).to_h | |
# {"data" => {"oldField" => "Old"}} | |
# Using the directive in a multiplex: | |
res = MySchema.multiplex( | |
[ | |
{ query: "query @changeset(version: \"2025-02-01\") { newField }" }, | |
{ query: "query @changeset(version: \"2025-02-01\") { oldField }" }, | |
{ query: "query @changeset(version: \"2024-02-01\") { oldField }" }, | |
] | |
) | |
pp res.map(&:to_h) | |
# [ | |
# {"data" => {"newField" => "New"}}, | |
# {"errors" => [{"message" => "Field 'oldField' doesn't exist on type 'Query'", "locations" => [{"line" => 1, "column" => 43}], "path" => ["query", "oldField"], "extensions" => {"code" => "undefinedField", "typeName" => "Query", "fieldName" => "oldField"}}]}, | |
# {"data" => {"oldField" => "Old"}} | |
# ] | |
puts MySchema.to_definition(context: { changeset_version: "2025-02-01" }) | |
# directive @changeset(version: String!) on MUTATION | QUERY | SUBSCRIPTION | |
# type Query { | |
# newField: String | |
# } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment