-
Notifications
You must be signed in to change notification settings - Fork 2k
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
RFC: Schema Language Directives #376
Conversation
This implements adding directives to the experimental schema language by extending the *locations* a directive can be used. Notice that this provides no semantic meaning to these directives - they are purely a mechanism for annotating an AST - however future directives which contain semantic meaning may be introduced in the future (the first will be `@deprecated`).
be4697d
to
fae564d
Compare
Also cc @OlegIlyenko, @freiksenet, and @josephsavona who have expressed opinions on this in the past. Barring any strong objections, I'd like to move forward with this, and will then amend the (currently thin) graphql/graphql-spec#90 |
Thanks for putting this together, @leebyron! I don't have any objections. I still feel that putting directives in front of the definitions would be a bit more comfortable. But I guess this comes from by background working with languages like java, scala, python, etc. I just feel that it's more common these days, thus it would be more familiar to most of the users. But it's just a minor thing. Do you plan to represent descriptions in IDL with directives as well? Also another question. There were a lot of different discussions around and directives/annotations, so the concept became a bit overloaded :) Here you explicitly mentioned that directives just annotate IDL AST nodes without any additional semantics. I was wondering whether you plan to define something that will expose additional (and user-defined) schema meta-information via introspection API (like, for instance, a list of annotations/directives on fields and types)? Several proposals mentioned this, if I remember correctly. |
I think descriptions will be most ergonomically represented as comments above the described definition. That follows the javadoc prior art to some degree, but I think it will just feel more natural. This proposal doesn't make suggestions as to how metadata in introspection or decorators (schema modifiers) should behave, but I'm excited about both ideas. What I'm hoping for here is just a common syntax we can use to start building both of those ideas. |
And of course I don't mean to discredit that placing these directives before feels more natural coming from Python or Java. I agree with that! I just find internal consistency in the language more valuable. |
👍 sounds great! Also, it was not mentioned that much these discussions, I think this addition would be a great help with cross-language compatibility tests (graphql/graphql-spec#72). This makes it possible to define a set of directives which will control behavior of the resolve function for the tests. |
case ENUM_VALUE_DEFINITION: return DirectiveLocation.ENUM_VALUE; | ||
case INPUT_OBJECT_TYPE_DEFINITION: return DirectiveLocation.INPUT_OBJECT; | ||
case INPUT_VALUE_DEFINITION: | ||
const parentNode = ancestors[ancestors.length - 3]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you need to check that 'ancestors.length >= 3' or does parser guarantee that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parser all but guarantees it. The only way this could end up being negative is if you assemble an invalid AST to provide to the validator, and then you probably have other problems on your hands.
This is awesome. I really like how you separated the concept of schema directives from their semantic meaning in the schema and the idea of implementing schema transforms to give the directives ability to influence the schema metadata. No objections from me, really looking forward to writing some directives on client-side types :) |
@leebyron: This is great, really moves the conversation about schema metadata forward! I'm guessing the next steps are to actually add the information to the schema generated by buildASTSchema and then decide how to expose it in schema introspection? I'd love to get started on that by opening a discussion thread, if it's okay with you? |
Yeah! Those are open questions for sure. There are a lot of use cases for these schema directives discussed, and details to work out. The immediate next steps after agreeing on and landing this syntax change will be introducing a @deprecated directive for the schema builder to use. Then I'm interested in furthering discussion for metadata and decorator uses |
Oh, one more question: is there a reason the schema itself cannot have directives? What I mean by the schema having a directive is something like this:
This would be similar to annotating the document in capnproto. |
It's not that it cannot, I just didn't add it yet here. I think it's a reasonable thing to add, I'll follow up |
@leebyron, thanks for this, it looks great for it's intent! If I've understood this RFC correctly, what it doesn't cover and which PR #334 proposes as a concept of annotations, is a formal way to:
Apart from the above directives are very similar to the annotations concept. I'm going to close PR #334 in favour of this one, although it doesn't fully cover the annotations concept but I believe I can work with this. |
Your phased rollout plan is very thoughtful. You mention that we use the "@" sigil to be consistent with other languages, but we're sticking with the postfix notation for historical reasons. Do you intend to revisit the pre/postfix decision (for consistency with ES7 decorators)? If so, is this something that might affect the upcoming implementation of the first few core/example directives? |
@clintwood - that's correct. This only introduces a syntax for expressing these kinds of directives/annotations in the schema language but offers no semantic meaning for them. Based on how each directive is intended to be used, I imagine some will allow defining metadata on a schema, some will allow defining decorator-style manipulations for the schema builder, some will allow defining client-side code generation artifacts, and I'm sure there are also future uses for them we haven't thought of yet. |
@robzhu We won't revisit pre/postfix because doing so would be highly disruptive to all previously written queries and with marginal value. I think that decision sailed when we first introduced directives (albeit before open sourcing) into the language in a postfix notation. Honestly I'm not too worried about the postfix notation - despite being different from some other languages it has proven to be an ergonomically valuable choice for Cap'n Proto, which was a major source of inspiration for this syntactic feature. |
* master: (26 commits) 0.6.0 Validation: improving overlapping fields quality (graphql#386) Validation: context.getFragmentSpreads now accepts selectionSet rather than fragment AST node Factor out more closure functions Factor out closure functions to normal functions Deprecated directive (graphql#384) RFC: Directive location: schema definition (graphql#382) RFC: Schema Language Directives (graphql#376) Export introspection in public API Export directive definitions. (graphql#381) BUG: Ensure building AST schema does not exclude @Skip and @include (graphql#380) documentation of schema constructor Revert "Remove all 'instanceof GraphQLSchema' checks" (graphql#377) remove all 'instanceof GraphQLSchema' checks (graphql#371) Error logging for new interface type semantics (graphql#350) Nit: Missing case in grammar for TypeSystemDefinition in comment Bug: printer can print non-parsable value Factor out suggestion quoting utility Minor refactoring Minor refactoring of error messages for unknown fields ...
This implements adding directives to the experimental schema language by extending the locations a directive can be used.
Notice that this provides no semantic meaning to these directives - they are purely a mechanism for annotating an AST - however future directives which contain semantic meaning may be introduced in the future (the first will be
@deprecated
). More specifically this means that there is no change to theGraphQLSchema
object and therefore also no changes to the introspection API.Because this is purely an way to annotate definitions within an AST, it provides (only) the basis for implementing all the related ideas which require this syntactic change:
@deprecated
directive and altering the existingbuildASTSchema
function to be aware of this.GraphQLSchema
object - perhaps this concept can be built by extendingbuildASTSchema
with a plugin model.Also, because this implements schema directives by extending the available locations of the existing directive definitions, this means that directives must be well-defined before they can be used. This enables validation to ensure that schema directives are used only in the way they are intended to be used.
Many huge thanks to everyone who's contributed to the thought process behind how best to implement this kind of schema directive. First proposed by @igorcanadi in #265, then later refined by @clintwood in #334 and keenly described by @helfer in a recent apollo post.
There have been many subtle variations on the actual grammatic form for these annotations that we can boil down to these few decisions:
Should schema directives accept arguments in a similar form to operation directives?
Just about every proposal so far has recommended this, so I think this is emphatic agreement.
Should the "sigil" character match operation directives, or be something new?
Each proposal has suggested a new character (
@directive
,@@directive
,+directive
and%directive
). I think it is prudent to have a unified syntax between language directives and schema directives as both a simplification and to ease any learning curve. By ensuring both kinds of directives appear the same, we can avoid any confusion between the two.Should schema directives be placed before or after the relevant definition?
This has been contested and both proposed, with more proposals favoring before by citing python decorators and java annotations as prior art. There's a lot of validity to this argument but I believe this boils down to internal consistency within the language. Because the existing directives are placed after the relevant definition and this proposal simply extends the existing directives language, it makes sense to remain consistent and also place schema directives after (or within, as is consistent) their relevant definitions. The original directives syntax for GraphQL was inspired by https://capnproto.org/language.html#annotations, so this decision continues to follow that prior art.