Giter Site home page Giter Site logo

Comments (15)

grxy avatar grxy commented on May 23, 2024 7

Hello @exAspArk, are there any plans for this library to support GraphQL Ruby 1.13 or 2.0? Are you open to PRs to address this issue?

from graphql-guard.

23tux avatar 23tux commented on May 23, 2024 4

I just tried to find a fix for this, but I'm not sure how to get the metadata from schema_member without using graphql_definition in those lines:

MASKING_FILTER = ->(schema_member, ctx) do
mask = schema_member.graphql_definition.metadata[:mask]
mask ? mask.call(ctx) : true
end

In sum there are 3 places where #graphql_definition is still used.

As mentioned here https://github.com/rmosolgo/graphql-ruby/blob/master/CHANGELOG.md#deprecations-3

All features using those legacy definitions are already removed and all behaviors should have been ported to class-based definitions. So, you should be able to remove those calls entirely.

But of course, we can't just remove the call itself, somehow it has to load the masks.

Maybe @rmosolgo can help?

from graphql-guard.

23tux avatar 23tux commented on May 23, 2024 1

@rmosolgo thanks for the quick answer!

It seems, that the changes require more work than I first anticipated to get masking to work. So I wondered, if you can give some advice how to implement it?

The current implementation is this:

def add_schema_masking!(schema_definition)
schema_definition.class_eval do
def self.default_filter
GraphQL::Filter.new(except: default_mask).merge(only: MASKING_FILTER)
end
end
end

I see some room for improvement here:

What would be a more future proof way of providing a masking feature? I found the visiblity stuff in your docs (see https://graphql-ruby.org/schema/dynamic_types.html#using-visiblecontext-1), but it seems that it's intended to dynamically switch the implementation of a type, right?

Regarding "metadata is part of the legacy type definition system": Does this imply, that using .accept_definitions is the wrong way now? See:

GraphQL::ObjectType.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
GraphQL::Field.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
GraphQL::Field.accepts_definitions(mask: GraphQL::Define.assign_metadata_key(:mask))
GraphQL::Schema::Object.accepts_definition(:guard)
GraphQL::Schema::Field.accepts_definition(:guard)
GraphQL::Schema::Field.accepts_definition(:mask)

Before you could write something like this

field :title, String, null: true, guard: ->(obj, args, ctx) { ctx[:current_user].admin? }

I'm not sure how I would achieve something like this using your approach with attr_accessor :mask. Could you elaborate?

from graphql-guard.

rmosolgo avatar rmosolgo commented on May 23, 2024 1

Yeah, there's not a way to install a field class for every base type in one line of code -- the base Object, Interface, and Mutation classes all need that configuration. I definitely agree that would be nice, but I haven't been able to figure out how it'd work...

from graphql-guard.

pierry01 avatar pierry01 commented on May 23, 2024

👍 up

from graphql-guard.

asgeo1 avatar asgeo1 commented on May 23, 2024

Hmm, I'm getting this error now on the latest graphql-ruby (1.13.4)

undefined method `graphql_definition' for #<GraphQL::Schema::TypeMembership
Did you mean?  graphql_name
/bundle/ruby/3.0.0/bundler/gems/graphql-guard-ca368a8dbdac/lib/graphql/guard.rb:17:in `block in <class:Guard>'

Not quite sure what's happening as I didn't think they removed the .graphql_definition yet? In the PR, it seems deprecated, not removed. Not quite following what's going on.

Downgrading to graphql 1.12.23 addresses the issue, and I no longer get the error.

from graphql-guard.

23tux avatar 23tux commented on May 23, 2024

Is there any news on this? I get the same warnings when updating to graphql-ruby 1.13.8

from graphql-guard.

23tux avatar 23tux commented on May 23, 2024

I just discovered, that it's not only a deprecation warning, but an error:

NoMethodError:
 undefined method `graphql_definition' for #<GraphQL::Schema::TypeMembership:0x0000557f69381178>
 Did you mean?  graphql_name
# /usr/local/bundle/gems/graphql-guard-2.0.0/lib/graphql/guard.rb:17:in `block in <class:Guard>'

from graphql-guard.

rmosolgo avatar rmosolgo commented on May 23, 2024

metadata is part of the legacy type definition system, you're right that there's no way to access it apart from .graphql_definition. Instead of .metadata, you should store custom values in instance variables on your definitions. For example:

module MaskFilter 
  attr_accessor :mask 
end 

class Types::BaseObject < GraphQL::Schema::Object
  extend MaskFilter 
end 

# ^^ do the same for other base classes 

MASKING_FILTER = ->(schema_member, ctx) do 
 mask =  schema_member.respond_to?(:mask) && schema_member.mask
 mask ? mask.call(ctx) : true 
end 

Hope that helps!

from graphql-guard.

rmosolgo avatar rmosolgo commented on May 23, 2024

future proof way of providing a masking feature?

Yes, def self.visible?(ctx) is the way. Here are some docs on that: https://graphql-ruby.org/authorization/visibility.html

Besides swapping implementations at runtime, you can also hide implementations at runtime -- and if a type, field, argument, etc is hidden, then it doesn't exist for the current query.

using .accept_definitions

Yes, it was a way to bridge the gap from legacy definition to class-based definition, but it's removed in graphql-ruby 2.0.

Honestly, for class-based definitions, I would recommend a method-based approach instead of a proc-based approach. Something like this:

module GraphQL::Guard::Integration 
  def masked?(context)
    # library users should implement this method to hide things
    false
  end 
  
  def visible?(context)
    (!masked?(context)) && super 
  end 

  def guarded?(*args) # for objects, `[obj, ctx]`, but for fields and arguments, `[obj, args, ctx]`
    # library users should implement this method to flag things as not authorized
    false 
  end 
  
  def authorized?(*args)
    (!guarded?(*args)) && super 
  end
end 

class Types::BaseObject < GraphQL::Schema::Object 
  extend GraphQL::Guard::Integration 
  
  def self.guarded?(obj, ctx)
    ctx[:current_user].admin?
  end 
end 

# or: 

class Types::BaseField < GraphQL::Schema::Field 
  include GraphQL::Guard::Integration 
  
  def guarded?(obj, args, ctx)
    ctx[:current_user].admin?
  end 
end 

More details about graphql-ruby's .authorized? method here: https://graphql-ruby.org/authorization/authorization.html

Hope that helps!

from graphql-guard.

mcelicalderon avatar mcelicalderon commented on May 23, 2024

@rmosolgo thank you, this helps a lot. We are going to need something similar in https://github.com/graphql-devise/graphql_devise and I think it might help for this gem too.

It looks like our only way to implement this, will be to provide a custom field class in the gem, and that one should be able to handle what you described in #53 (comment). Is there a way to assign a default field_class for all types of fields? From the docs it'd seem like we will have to call field_class in every base type like enum or object. But from a gem's perspective it would be amazing if we could assign a field class for ALL in a single call. Of course, I see how that might not be possible and we might have to document this so users do this in their projects for every base type.

from graphql-guard.

mcelicalderon avatar mcelicalderon commented on May 23, 2024

That's fine, thank you!

from graphql-guard.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.