Fill in directive argument defaults when not supplied - #834
Open
oryan-block wants to merge 1 commit into
Open
oryan-block wants to merge 1 commit into
oryan-block wants to merge 1 commit into
Conversation
When a directive was applied without some of its arguments, the applied directive and the legacy GraphQLDirective view only carried the arguments written in the SDL. Arguments declared with a default value in the directive definition were dropped, so directive wirings and anything reading the schema saw no value for them, e.g. a bare @email had no "message" even though the definition gives it a default. graphql-java's SchemaGenerator transfers those defaults onto every applied directive. buildAppliedDirectives and buildDirectives now add every definition argument that has a default and wasn't supplied, with the default as its value. This replaces the special case that only did so for the "reason" of a bare @deprecated. Both functions are used for every directive location, so this covers types, fields, arguments, input fields, enum values, directive arguments and the schema itself. The legacy directives of an input field are still built from the input object's directives, which is a separate bug (#731). As in graphql-java, SchemaPrinter now prints the filled in arguments, e.g. a bare @email prints as @email(message : "..."). Fixes #443 Fixes #821 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
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.




Fixes #443
Fixes #821
Checklist
Description
When a directive is applied without an argument that has a default value, the default never shows up. Take the example from #443:
directive @Email(message: String = "{path} must be a valid email") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION, applied as a bare@EmailonupdatePersonEmail(email: String @Email). Inside theSchemaDirectiveWiring, neitherenv.appliedDirectivenorenv.directivehas amessageargument. alacoste hit the same thing with anon FIELD_DEFINITIONdirective inonField, and there's no way around it. #821 is the general version: withdirective @auth(role: String = "USER") on FIELD_DEFINITIONandsecret: String @auth, graphql-java'sSchemaGeneratorgivesroleas"USER"and we give null.SchemaParser.buildAppliedDirectivesandbuildDirectivesonly looped over the arguments written in the SDL. So definition arguments that weren't supplied were dropped from both theGraphQLAppliedDirectiveand the legacyGraphQLDirective. The only exception was the special case from #818 for thereasonof a bare@deprecated, and only on the applied directive. graphql-java'sSchemaGeneratorfills these in for every location (SchemaGeneratorAppliedDirectiveHelper.transferMissingAppliedArgumentsandtransferMissingArguments).Now both functions add every definition argument that has a default and wasn't supplied, with the default as its value. This replaces the
@deprecatedspecial case, and a bare@deprecatedstill gets itsreason. Both functions are used for every directive location, so this covers types, fields, arguments, input fields, enum values, arguments of directive definitions and the schema itself (applied directives only, the schema has no legacy view). The newDirectiveTestcase checks both views at wiring time inonFieldandonArgument, plus the applied view on an input field, the schema and an enum value. It fails on master withemail=(null, null). I also compared against graphql-java 26.1'sSchemaGeneratorwith a scratch test (not committed) and got the sameSchemaPrinteroutput and the same values, including enum, list, input object and non-null defaults.On input fields the legacy
env.directive(andfield.getDirective(...)) is still null. That's because the legacy directives of an input field are built from the input object's directives instead of the field's. It's an older bug, #731, and its fix also touchesDirectiveWiringHelper, so I kept it out of this one. The applied view on input fields is correct and tested. I also didn't copy two smaller things graphql-java does. It adds missing arguments that have no default, with no value set. We still leave those out, sogetArgument(name)returns null for them instead of an argument without a value (getValue()andSchemaPrintercan't tell the difference). It also setsdefaultValueon the legacyGraphQLArgument, where we only set the value, same as for supplied arguments. Unrelated, but enum typed directive arguments still read as null withgetValue()at wiring time, for supplied values as well as defaults. Same as on master.Behaviour change: applied directives and legacy directives now include the defaulted arguments the SDL leaves out, so wirings,
getArgument(...)and introspection of applied directives see the default instead of null.SchemaPrinterprints them too, e.g. a bare@emailnow prints as@email(message : "{path} must be a valid email"), same as graphql-java'sSchemaGenerator. So snapshot tests of printed SDL (or a federation_service.sdl) will show diffs. The legacy view of a bare@deprecatednow also has itsreason("No longer supported").deprecationReasonand the printed output don't change. Undeclared directives (allowUndeclaredDirectives) have no definition, so nothing changes for them. As #821 says, this should go in a minor release with a note in the release notes.🤖 Generated with Claude Code