From 1dc971eb498b1ad10423f3d542018cf402bcb73e Mon Sep 17 00:00:00 2001 From: pelletier197 Date: Thu, 1 Oct 2020 21:31:14 -0400 Subject: [PATCH] fix schema wiring (#30) (cherry picked from commit d70dbe62873b3189d82c547d365e0bf9c90dc9c6) --- .../FieldValidatorDataFetcher.java | 79 +++++++++++++++++++ .../schemawiring/ValidationSchemaWiring.java | 44 ++++------- 2 files changed, 94 insertions(+), 29 deletions(-) create mode 100644 src/main/java/graphql/validation/schemawiring/FieldValidatorDataFetcher.java diff --git a/src/main/java/graphql/validation/schemawiring/FieldValidatorDataFetcher.java b/src/main/java/graphql/validation/schemawiring/FieldValidatorDataFetcher.java new file mode 100644 index 0000000..a02836a --- /dev/null +++ b/src/main/java/graphql/validation/schemawiring/FieldValidatorDataFetcher.java @@ -0,0 +1,79 @@ +package graphql.validation.schemawiring; + +import graphql.GraphQLError; +import graphql.schema.*; +import graphql.validation.interpolation.MessageInterpolator; +import graphql.validation.rules.OnValidationErrorStrategy; +import graphql.validation.rules.TargetedValidationRules; +import graphql.validation.rules.ValidationRule; +import graphql.validation.rules.ValidationRules; +import graphql.validation.util.Util; + +import java.util.List; +import java.util.Locale; + +public class FieldValidatorDataFetcher implements DataFetcher { + private final OnValidationErrorStrategy errorStrategy; + private final MessageInterpolator messageInterpolator; + private final DataFetcher defaultDataFetcher; + private final Locale defaultLocale; + private final ValidationRules validationRules; + private TargetedValidationRules applicableRules; + + public FieldValidatorDataFetcher(OnValidationErrorStrategy errorStrategy, + MessageInterpolator messageInterpolator, + DataFetcher defaultDataFetcher, + Locale defaultLocale, + ValidationRules validationRules) { + this.errorStrategy = errorStrategy; + this.messageInterpolator = messageInterpolator; + this.defaultDataFetcher = defaultDataFetcher; + this.defaultLocale = defaultLocale; + this.validationRules = validationRules; + this.applicableRules = null; + } + + @Override + public Object get(DataFetchingEnvironment environment) throws Exception { + if (!wereApplicableRulesFetched()) { + fetchApplicableRules(environment); + } + + // When no validation is performed, this data fetcher is a pass-through + if (applicableRules.isEmpty()) { + return defaultDataFetcher.get(environment); + } + + List errors = applicableRules.runValidationRules(environment, messageInterpolator, defaultLocale); + if (!errors.isEmpty()) { + if (!errorStrategy.shouldContinue(errors, environment)) { + return errorStrategy.onErrorValue(errors, environment); + } + } + + Object returnValue = defaultDataFetcher.get(environment); + if (errors.isEmpty()) { + return returnValue; + } + return Util.mkDFRFromFetchedResult(errors, returnValue); + } + + private void fetchApplicableRules(DataFetchingEnvironment environment) { + final GraphQLFieldDefinition field = environment.getFieldDefinition(); + final GraphQLFieldsContainer container = asContainer(environment); + + applicableRules = validationRules.buildRulesFor(field, container); + } + + private GraphQLFieldsContainer asContainer(DataFetchingEnvironment environment) { + final GraphQLType parent = environment.getParentType(); + if (parent == null) { + return null; + } + return (GraphQLFieldsContainer) environment.getParentType(); + } + + private boolean wereApplicableRulesFetched() { + return applicableRules != null; + } +} diff --git a/src/main/java/graphql/validation/schemawiring/ValidationSchemaWiring.java b/src/main/java/graphql/validation/schemawiring/ValidationSchemaWiring.java index 26d9c97..36cf6ba 100644 --- a/src/main/java/graphql/validation/schemawiring/ValidationSchemaWiring.java +++ b/src/main/java/graphql/validation/schemawiring/ValidationSchemaWiring.java @@ -1,6 +1,5 @@ package graphql.validation.schemawiring; -import graphql.GraphQLError; import graphql.PublicApi; import graphql.schema.DataFetcher; import graphql.schema.GraphQLFieldDefinition; @@ -11,17 +10,15 @@ import graphql.validation.rules.OnValidationErrorStrategy; import graphql.validation.rules.TargetedValidationRules; import graphql.validation.rules.ValidationRules; -import graphql.validation.util.Util; -import java.util.List; import java.util.Locale; /** - * A {@link graphql.schema.idl.SchemaDirectiveWiring} that can be used to inject validation rules into the data fetchers + * A {@link SchemaDirectiveWiring} that can be used to inject validation rules into the data fetchers * when the graphql schema is being built. It will use the validation rules and ask each one of they apply to the field and or its * arguments. *

- * If there are rules that apply then it will it will change the {@link graphql.schema.DataFetcher} of that field so that rules get run + * If there are rules that apply then it will it will change the {@link DataFetcher} of that field so that rules get run * BEFORE the original field fetch is run. */ @PublicApi @@ -38,40 +35,29 @@ public GraphQLFieldDefinition onField(SchemaDirectiveWiringEnvironment currentDF = env.getCodeRegistry().getDataFetcher(fieldsContainer, fieldDefinition); + final DataFetcher newDF = buildValidatingDataFetcher(errorStrategy, messageInterpolator, currentDF, locale); env.getCodeRegistry().dataFetcher(fieldsContainer, fieldDefinition, newDF); return fieldDefinition; } - private DataFetcher buildValidatingDataFetcher(TargetedValidationRules rules, OnValidationErrorStrategy errorStrategy, MessageInterpolator messageInterpolator, DataFetcher currentDF, final Locale defaultLocale) { - // ok we have some rules that need to be applied to this field and its arguments - return environment -> { - List errors = rules.runValidationRules(environment, messageInterpolator, defaultLocale); - if (!errors.isEmpty()) { - // should we continue? - if (!errorStrategy.shouldContinue(errors, environment)) { - return errorStrategy.onErrorValue(errors, environment); - } - } - // we have no validation errors or they said continue so call the underlying data fetcher - Object returnValue = currentDF.get(environment); - if (errors.isEmpty()) { - return returnValue; - } - return Util.mkDFRFromFetchedResult(errors, returnValue); - }; + private DataFetcher buildValidatingDataFetcher(OnValidationErrorStrategy errorStrategy, + MessageInterpolator messageInterpolator, + DataFetcher currentDF, + final Locale defaultLocale) { + return new FieldValidatorDataFetcher( + errorStrategy, + messageInterpolator, + currentDF, + defaultLocale, + ruleCandidates + ); } }