palkan / action_policy-graphql

Action Policy integration for GraphQL
MIT License
152 stars 9 forks source link

Field extensions should not modify options hash #49

Closed gael-ian closed 10 months ago

gael-ian commented 10 months ago

Hello,

We are on our way to implement pre-authorization on fields in our GraphQL schema and on mutations in particular. We have quite a lot of them and, to reduce redundant declaration, we'd like to use the .with_options method provided by ActiveSupport to merge options common to mutation field declarations around the same model.

Environment

Ruby Version: 3.2
Framework Version: Rails 7.1
Action Policy Version: 0.6.7
Action Policy GraphQL Version: 0.5.3

What did we do?

class Mutation < Types::Objects::Base
  with_options preauthorize: { with: ThingPolicy } do
    field :thing_create, mutation: Mutations::Things::Create
    field :thing_update, mutation: Mutations::Things::Update
  end
end

What did we expect to happen?

with_options should work as expected and actually forward options to every .field call.

What actually happened?

with_options works as expected but field extensions consume options in a destructive way: as they internally use Hash#delete on the options hash, the first field is correctly extended but subsequent fields receive empty options.


This can be fixed in a minimalist way with something like:

# In action_policy/graphql/authorized_field.rb
module ActionPolicy::GraphQL::AuthorizedField
  class Extension < ::GraphQL::Schema::FieldExtension
+   def initialize(field:, options:) = super(field:, options: options&.dup || {})
+
    def extract_option(key, &default)
      value = options.fetch(key, &default)
      options.delete key
      value
    end
  end
end

Note: This will not be fixed in graphql-ruby. See rmosolgo/graphql-ruby#4733.

palkan commented 10 months ago

Thanks for the report and the suggested fix! Released in 0.5.4