From 2dd6afebdd9e848eef1e192f5212038a6a0de45b Mon Sep 17 00:00:00 2001 From: Sean Kirby Date: Tue, 28 May 2024 19:53:55 -0400 Subject: [PATCH] stop relying on :schema_generation_context? to avoid visibility rules There is a built-in alternative that doesn't leaks all over client code. --- CHANGELOG.md | 16 +++++++ README.md | 44 +------------------ lib/nulogy_graphql_api.rb | 1 - .../schema/base_mutation.rb | 12 ----- .../tasks/schema_generator.rb | 29 +++++------- 5 files changed, 29 insertions(+), 73 deletions(-) delete mode 100644 lib/nulogy_graphql_api/schema/base_mutation.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index dc1c4da..545bec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ _none_ +## 4.0.0 (2024-05-28) + +**Changes** + +* Remove the `schema_generation_context?` attribute to the GraphQL `context` when generating the schema. Use the + already available `GraphQL::Schema::AlwaysVisible` plugin instead. + * **(Breaking)** Remove the `NulogyGraphqlApi::Schema::BaseMutation` class which introduced a new API for the + `visible?` method that took a block. This introduced a deviation from the ruby graphql gem's API only for + Mutations and so it was removed. Please ensure that any invocations of `visible?` do not take a block and use + `GraphQL::Schema::Mutation` instead. + * **(Breaking)** Change the `NulogyGraphqlApi::Tasks::SchemaGenerator#generate_schema` method to output the + stringified version of the schema instead of checking it for changes and writing it to a file. + * Expose the `#check_changes` and `#write_schema_to_file` methods on the + `NulogyGraphqlApi::Tasks::SchemaGenerator` to give the user more control over how to build their + tooling. + ## 3.0.1 (2024-01-30) * Add `include_graphql_error` RSpec matcher diff --git a/README.md b/README.md index c8a5346..30c1547 100644 --- a/README.md +++ b/README.md @@ -130,8 +130,6 @@ end There is a Rake task to generate the `schema.graphql` file. You need to provide the `schema_file_path` and the schema class so that the task can detect breaking changes and generate the file. If you don't have a schema file because it's your first time generating it then the rake task will just create one for you in the path provided. -There is also a third argument `context`. You'll have to configure it to be able to generate the SDL of fields or types that are only visible for more privileged users. - ```ruby namespace :graphql_api do desc "Generate the graphql schema of the api." @@ -142,47 +140,7 @@ namespace :graphql_api do NulogyGraphqlApi::Tasks::SchemaGenerator .new(schema_file_path, schema) - .generate_schema - end -end -``` - -### Node visibility - -When you customize the visibility of parts of your graph you have to make sure that all nodes are visible when the schema is being generated by the rake task. You can do so by using the `schema_generation_context?` attribute that is added to the context by the `SchemaGenerator` mentioned in the previous section. - -Here is how to use it: - -##### On fields -```ruby -field :entity, MyApp::EntityType, null: false do - description "Find an entity by ID" - argument :id, ID, required: true - - def visible?(context) - context[:schema_generation_context?] || context[:current_user].superuser? - end -end -``` - - -##### On mutations - -In this case the `schema_generation_context?` attribute is checked by the `BaseMutation` class. All you have to do is inheriting from it and override `visible?` passing a block to the base method. - -```ruby -module MyApp - class CreateEntity < NulogyGraphqlApi::Schema::BaseMutation - field :entity, MyApp::EntityType, null: false - field :errors, [NulogyGraphqlApi::Types::UserErrorType], null: false - - def self.visible?(context) - super { context[:current_user].super_user? } - end - - def resolve(args) - # ... - end + .write_schema_to_file end end ``` diff --git a/lib/nulogy_graphql_api.rb b/lib/nulogy_graphql_api.rb index acf8d87..391935f 100644 --- a/lib/nulogy_graphql_api.rb +++ b/lib/nulogy_graphql_api.rb @@ -3,7 +3,6 @@ require "nulogy_graphql_api/error_handling" require "nulogy_graphql_api/graphql_executor" require "nulogy_graphql_api/graphql_response" -require "nulogy_graphql_api/schema/base_mutation" require "nulogy_graphql_api/transaction_service" require "nulogy_graphql_api/tasks/schema_changes_checker" require "nulogy_graphql_api/tasks/schema_generator" diff --git a/lib/nulogy_graphql_api/schema/base_mutation.rb b/lib/nulogy_graphql_api/schema/base_mutation.rb deleted file mode 100644 index d1f2db8..0000000 --- a/lib/nulogy_graphql_api/schema/base_mutation.rb +++ /dev/null @@ -1,12 +0,0 @@ -module NulogyGraphqlApi - module Schema - class BaseMutation < GraphQL::Schema::Mutation - def self.visible?(context) - return true if context[:schema_generation_context?] - return super && yield if block_given? - - super - end - end - end -end diff --git a/lib/nulogy_graphql_api/tasks/schema_generator.rb b/lib/nulogy_graphql_api/tasks/schema_generator.rb index 5702b50..05cf2a3 100644 --- a/lib/nulogy_graphql_api/tasks/schema_generator.rb +++ b/lib/nulogy_graphql_api/tasks/schema_generator.rb @@ -4,37 +4,32 @@ class SchemaGenerator def initialize(schema_output_path, schema, context: {}) @schema_output_path = schema_output_path @schema = schema - @context = context.merge( - schema_generation_context?: true - ) + @context = context end def generate_schema - check_changes - write_schema_to_file + # We will want to create a subclass of the schema here to make sure we don't pollute the original schema. + GraphQL::Schema::AlwaysVisible.use(@schema) + @schema.to_definition(context: @context) end - private - def check_changes return if old_schema.blank? - SchemaChangesChecker.new.check_changes(old_schema, @schema) - end - - def old_schema - return unless File.exist?(@schema_output_path) - - File.read(@schema_output_path) + SchemaChangesChecker.new.check_changes(old_schema, generate_schema) end def write_schema_to_file - File.write(@schema_output_path, schema_definition) + File.write(@schema_output_path, generate_schema) puts Rainbow("\nSuccessfully updated #{@schema_output_path}").green end - def schema_definition - GraphQL::Schema::Printer.print_schema(@schema, context: @context) + private + + def old_schema + return unless File.exist?(@schema_output_path) + + File.read(@schema_output_path) end end end