feat: Support custom Type-Directives#806
Open
michael-georgiadis wants to merge 12 commits into
Open
Conversation
Collaborator
|
So, I don't really have an issue with this. I'd need to review in further detail. But, I think we should probably separate this out into 2 PRs - one that adds support for the built-in GraphQL directives, first. And then the custom directive overlay. I thought we already had the I think having this broken apart will help to reason about it more clearly. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This adds a way for you to configure your own directives in GraphQLite using PHP attributes and registering them on the schema.
They split in two. Pure metadata ones or with some run behavior. I am expecting a debate on this cause they do look a lot like middleware. Happy to reach somewhere with it tho.
It also includes the
@oneOfwhich is built in.Why
GraphQLite has always been a pain to deal with when directives come into play. I have used it in one company that we wanted to have federated support and we had to hack a lot of internals to add them and then now a teammate also had to use the ClassFinder class of the library to wire the
@oneOfdirective and keep the GraphQLite feel in our implementationIn my opinion (and it is purely my opinion ofc), if webonyx supports directives, GraphQLite should do too.
How it works
A directive is a PHP attribute class that implements one of the family interfaces,
which is what ties it to a GraphQL location:
FieldDirectiveFIELD_DEFINITIONInputFieldDirectiveINPUT_FIELD_DEFINITIONObjectTypeDirectiveOBJECTInputObjectTypeDirectiveINPUT_OBJECTImplementing the interface alone gives you a metadata-only directive: it's registered on the schema and shows up in introspection, but does nothing at runtime. To actually do something, implement the matching
Behavioral*sub-interface, which adds an apply hook dispatched through a middleware pipe.The pieces, each with one job:
namespaces, reusing the existing class-finder cache.
cover the declared locations, and the implemented interface has to match the location.
arguments (as GraphQL args), its repeatability, and the webonyx Directive to register.
(and the built-in override rule), stores the result, and answers lookups.
What ends up in the schema
SDL (directive @uppercase on FIELD_DEFINITION) and in introspection alongside the
webonyx built-ins.
@auditon a field, the application is recorded onthe element's astNode->directives, but it is not printed in the SDL.
That last point is on purpose: webonyx's SchemaPrinter doesn't print directive applications (only
@deprecatedand@oneOf, which it special-cases), and we follow that behavior rather than shipping a parallel printer GraphQLite would have to maintain. The applications are still attached to the AST, so anyone who needs them in SDL (Apollo Federation's @key, schema tooling) can plug in their own printer.Notable decisions
@oneOfas a built-in.#[OneOf]on an#[Input]class flips webonyx'sisOneOfflag. webonyx already declares
@oneOf, so we don't register a second definition for it(DirectiveDefinition::$builtIn = true). Users can override a built-in by shipping theirown class with the same name.
Scope / not included
INTERFACE, SCHEMA, …) are present in the DirectiveLocation enum but not wired yet.
these are type-system directives declared by the API author.