Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I use these custom directives? #3

Open
ahokinson opened this issue Dec 12, 2018 · 3 comments
Open

How do I use these custom directives? #3

ahokinson opened this issue Dec 12, 2018 · 3 comments

Comments

@ahokinson
Copy link

ahokinson commented Dec 12, 2018

Do I need to add them to the Schema creation under directives or add them as middleware to GraphQL?

I'm really interested in writing my own directives to inject some code to remove/add to my query (as is suggested here) and your repo seems like a good framework to achieve this with Graphene (which is lacking any documentation on implementing custom directives).

Right now, I'm getting this error:

AssertionError: Schema directives must be List[GraphQLDirective] if provided but got: [<class 'core.directives.numbers.FloorDirective'>].

Do you have any advice for getting these to work? (I know this repo is 2 years old)

@timkindberg
Copy link

I have the same question... how the heck do you use these, and how do I write my own?!

@janbaykara
Copy link

janbaykara commented Aug 24, 2019

According to the tests:

  1. Create directive classes that inherit from the BaseCustomDirective (explanation below):
    class ShuffleDirective(BaseCustomDirective):
    @staticmethod
    def process(value, directive, root, args, context, info):
    if value:
    random.shuffle(value)
    return value
  2. Add the middleware
    result = schema.execute(query, middleware=[CustomDirectivesMiddleware()])
  3. Initialise the schema with all these directives
    schema = graphene.Schema(query=QueryRoot, directives=CustomDirectiveMeta.get_all_directives())

Now the middleware runs on every resolver, looping through the registered and initialised and installed directives

for directive in field.directives:
directive_class = CustomDirectiveMeta.REGISTRY[directive.name.value]
new_value = directive_class.process(new_value, directive, root, args, context, info)

The predefined directives in this package seem to register themselves due to their inheritance of the BaseCustomDirective class...

class ShuffleDirective(BaseCustomDirective):

class BaseCustomDirective(six.with_metaclass(CustomDirectiveMeta, GraphQLDirective)):
__metaclass__ = CustomDirectiveMeta

... which itself relies on CustomDirectiveMeta which auto-registers itself to the middleware:
class CustomDirectiveMeta(type):
REGISTRY = {} # Maps between ndb.Model to its GraphQL type
def __new__(mcs, name, bases, attrs):
newclass = super(CustomDirectiveMeta, mcs).__new__(mcs, name, bases, attrs)
if name != 'BaseCustomDirective':
mcs.register(newclass)
return newclass
@classmethod
def register(mcs, target):
mcs.REGISTRY[target.get_name()] = target

All the registered directives are pulled into the schema via that get_all_directives:

@classmethod
def get_all_directives(cls):
return [d() for d in cls.REGISTRY.values()]

Writing directives themselves seems pretty simple: they are wrapper functions for resolvers which, as we saw from the above code examples, relies on a static process method:

class ShuffleDirective(BaseCustomDirective):
@staticmethod
def process(value, directive, root, args, context, info):
if value:
random.shuffle(value)
return value

@janbaykara
Copy link

I've also had to change the root, args, context, info pattern of arguments in CustomDirectivesMiddleware to the root, info pattern of the latest Graphene lib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants