Skip to content

Instantly share code, notes, and snippets.

@tsunammis
Last active May 15, 2019 13:29
Show Gist options
  • Save tsunammis/0eeec3f7ec221076821f94d37cb3b2b8 to your computer and use it in GitHub Desktop.
Save tsunammis/0eeec3f7ec221076821f94d37cb3b2b8 to your computer and use it in GitHub Desktop.
Directive

One missing part needed by the community to provide external directives is a way to configure the directive.

Here is a draft of the API to provide configuration.

No more Directive abstract class

The Directive classes won't extend any tartiflette abstract classes. Instead, you will have to implement the methods you want to support depending on the feature you want to compliant with. (see above regarding the feature set)

from

from tartiflette.directive import Directive, CommonDirective

@Directive("myDirective")
class MyDirective(CommonDirective):
    pass

to

from tartiflette.directive import Directive

@Directive("myDirective")
class MyDirective:
    pass

Pass configuration at build time to a third party library

This is currently impossible to configure a directive/scalar (pass configuration as API Key, URL etc ...). The directives are a set of static methods (the same behavior is applied on every engine contained in your application).

Why adding a configuration to Directive/Scalar?

The Tartiflette DNA is to provide as much as possible an extensible Engine. We decided to base our extensibility on the Directive feature of the GraphQL Specification. It will allow the developers to hook some behaviors at different stages (build and execution time) of the Engine.

Here are some interesting features which could be created:

  • Directive to apply JSON Schema validation on input types.
  • Directive to add monitoring on specific fields
  • Directive to apply access rules on fields (e.g @auth) with dynamic introspection which will allow the developer to hide the fields from the introspection.
  • Directive to map the resolution of a field dirrectly to the result of an AWS Lambda / GCP Function

and so one... let your imagination take you away.

Configuration proposal

engine = Engine(
    sdl,
    modules=[
        "yourapp.query_resolvers",
        "yourapp.mutation_resolvers",
        {
            "name": "tartiflette_external_lib",
            "config": {
                "your": "configuration",
                "foo": {
                    "bar": "baz"
                }
            }
        }
    ]
)

Based on the current modules property (which currently allow only string), add a new kind of entry with that shape.

{
    "name": "string",
    "config": "dict"
}

How to deal with the configuration within a third party library?

This configuration will helps the tartiflette users to configure the library third party librarythey want to use.

For the Tartiflette developers, they will have to handle this configuration within their packages.

The idea is to give ability to the tartiflette developers to provide Tartiflette objects (directives, scalars, resolvers and so on) to the community, easily.

Context

Package name: tartiflette-directive-validators-jsonschema
Package main module name: tartiflette_directive_validators_jsonschema

Access the configuration at bake time.

The Engine will guess the method named bake(schema_name: str, config: dict) at the root level of the module.

e.g ./tartiflette_directive_validators_jsonschema/init.py

from tartiflette import Directive

from tartiflette_directive_validators_jsonschema.validate_by_ref import ValidateByRef

async def bake(schema_name: str, config: dict) -> str:
    sdl = """
    directive @validateByRef(
        ref: String!
    ) on ARGUMENT_DEFINITION
    """

    Directive("validateByRef", schema_name=schema_name)(ValidateByRef(config))

    return sdl

e.g ./tartiflette_directive_validators_jsonschema/validate_by_ref.py

class ValidateByRef:
    def __init__(self, config):
        # API Key ...
        # File path ...
        pass

    async def on_argument_execution(
        self,
        directive_args: Dict[str, Any],
        next_directive: Callable,
        argument_definition: "GraphQLArgument",
        args: Dict[str, Any],
        ctx: Optional[Dict[str, Any]],
        info: "Info",
    ) -> Any:
        pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment