From cd974f7a36b470020a8bbbca470aedf423beec62 Mon Sep 17 00:00:00 2001 From: hantsy Date: Sat, 25 Sep 2021 17:57:54 +0800 Subject: [PATCH] feat: add graphql-java-validation module --- buildSrc/src/main/kotlin/Versions.kt | 1 + .../build.gradle.kts | 23 +++++ .../ValidationRulesBuilderCustomizer.java | 23 +++++ .../DgsExtendedValidationAutoConfiguration.kt | 65 ++++++++++++++ ...itional-spring-configuration-metadata.json | 11 +++ .../main/resources/META-INF/spring.factories | 2 + .../autoconfig/BeanValidationSizeSmokeTest.kt | 86 +++++++++++++++++++ ...xtendedValidationAutoConfigurationTests.kt | 38 ++++++++ graphql-dgs-platform/build.gradle.kts | 3 + settings.gradle.kts | 1 + 10 files changed, 253 insertions(+) create mode 100644 graphql-dgs-extended-validation/build.gradle.kts create mode 100644 graphql-dgs-extended-validation/src/main/java/com/netflix/graphql/dgs/autoconfig/ValidationRulesBuilderCustomizer.java create mode 100644 graphql-dgs-extended-validation/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfiguration.kt create mode 100644 graphql-dgs-extended-validation/src/main/resources/META-INF/additional-spring-configuration-metadata.json create mode 100644 graphql-dgs-extended-validation/src/main/resources/META-INF/spring.factories create mode 100644 graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/BeanValidationSizeSmokeTest.kt create mode 100644 graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfigurationTests.kt diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 4463e81501..a0fc7f3dba 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -22,6 +22,7 @@ object Versions { const val SPRING_CLOUD_VERSION = "Hoxton.SR10" const val GRAPHQL_JAVA = "17.3" const val GRAPHQL_JAVA_EXTENDED_SCALARS = "17.0" + const val GRAPHQL_JAVA_EXTENDED_VALIDATION = "17.0" const val GRAPHQL_JAVA_FEDERATION = "0.7.0" const val JACKSON_BOM = "2.12.3" } diff --git a/graphql-dgs-extended-validation/build.gradle.kts b/graphql-dgs-extended-validation/build.gradle.kts new file mode 100644 index 0000000000..3508d43aa5 --- /dev/null +++ b/graphql-dgs-extended-validation/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +dependencies { + api(project(":graphql-dgs")) + api("com.graphql-java:graphql-java-extended-validation") + implementation("org.springframework.boot:spring-boot-autoconfigure") + + testImplementation(project(":graphql-dgs-spring-boot-starter")) +} diff --git a/graphql-dgs-extended-validation/src/main/java/com/netflix/graphql/dgs/autoconfig/ValidationRulesBuilderCustomizer.java b/graphql-dgs-extended-validation/src/main/java/com/netflix/graphql/dgs/autoconfig/ValidationRulesBuilderCustomizer.java new file mode 100644 index 0000000000..00df25bb2c --- /dev/null +++ b/graphql-dgs-extended-validation/src/main/java/com/netflix/graphql/dgs/autoconfig/ValidationRulesBuilderCustomizer.java @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.netflix.graphql.dgs.autoconfig; + +import graphql.validation.rules.ValidationRules; + +@FunctionalInterface +public interface ValidationRulesBuilderCustomizer { + void customize(ValidationRules.Builder builder); +} diff --git a/graphql-dgs-extended-validation/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfiguration.kt b/graphql-dgs-extended-validation/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfiguration.kt new file mode 100644 index 0000000000..dc2a8a4ffd --- /dev/null +++ b/graphql-dgs-extended-validation/src/main/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfiguration.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2021 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.graphql.dgs.autoconfig + +import com.netflix.graphql.dgs.DgsComponent +import com.netflix.graphql.dgs.DgsRuntimeWiring +import graphql.schema.idl.RuntimeWiring +import graphql.validation.rules.ValidationRules +import graphql.validation.schemawiring.ValidationSchemaWiring +import org.springframework.beans.factory.ObjectProvider +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@ConditionalOnClass(graphql.validation.rules.ValidationRules::class) +@ConditionalOnProperty( + prefix = "dgs.graphql.extensions.validation", + name = ["enabled"], + havingValue = "true", + matchIfMissing = true +) +@Configuration(proxyBeanMethods = false) +open class DgsExtendedValidationAutoConfiguration { + + @Bean + open fun defaultExtendedValidationRegistrar(validationRulesCustomizerProvider: ObjectProvider): DefaultExtendedValidationRegistrar { + return DefaultExtendedValidationRegistrar(validationRulesCustomizerProvider) + } + + @DgsComponent + @FunctionalInterface + fun interface ExtendedValidationRegistrar { + fun addValidationRules(builder: RuntimeWiring.Builder): RuntimeWiring.Builder + } + + open class DefaultExtendedValidationRegistrar(private val validationRulesCustomizerProvider: ObjectProvider) : + ExtendedValidationRegistrar { + + @DgsRuntimeWiring + override fun addValidationRules(builder: RuntimeWiring.Builder): RuntimeWiring.Builder { + val validationRulesBuilder = ValidationRules.newValidationRules() + validationRulesCustomizerProvider.ifAvailable { it.customize(validationRulesBuilder) } + + val validationRules = validationRulesBuilder.build() + val schemaWiring = ValidationSchemaWiring(validationRules) + // we add this schema wiring to the graphql runtime + return builder.directiveWiring(schemaWiring) + } + } +} diff --git a/graphql-dgs-extended-validation/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/graphql-dgs-extended-validation/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000000..54248c8abe --- /dev/null +++ b/graphql-dgs-extended-validation/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,11 @@ +{ + "groups": [], + "properties": [ + { + "name": "dgs.graphql.extensions.validation.enabled", + "type": "java.lang.Boolean", + "description": "If enabled, will provide an auto-configuration that will by default registered the Bean Validation Extensions available in graphql-java-extended-validation for the DGS Framework." + } + ], + "hints": [] +} \ No newline at end of file diff --git a/graphql-dgs-extended-validation/src/main/resources/META-INF/spring.factories b/graphql-dgs-extended-validation/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..bbe74a9ffc --- /dev/null +++ b/graphql-dgs-extended-validation/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.netflix.graphql.dgs.autoconfig.DgsExtendedValidationAutoConfiguration \ No newline at end of file diff --git a/graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/BeanValidationSizeSmokeTest.kt b/graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/BeanValidationSizeSmokeTest.kt new file mode 100644 index 0000000000..bbd3d60848 --- /dev/null +++ b/graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/BeanValidationSizeSmokeTest.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2021 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.graphql.dgs.autoconfig + +import com.netflix.graphql.dgs.* +import graphql.schema.idl.SchemaParser +import graphql.schema.idl.TypeDefinitionRegistry +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.SpringBootConfiguration +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.test.context.SpringBootTest +import java.util.* + +@SpringBootTest(classes = [BeanValidationSizeSmokeTest.LocalApp::class]) +@EnableAutoConfiguration +internal class BeanValidationSizeSmokeTest { + + @Autowired + lateinit var queryExecutor: DgsQueryExecutor + + @Test + fun createPostInputValidationFailed() { + val query = "mutation newPost(\$input: CreatePostInput!){ createPost(createPostInput: \$input) }" + var variables = mapOf( + "input" to mapOf( + "title" to "test", + "content" to "test content" + ) + ) + val executionResult = queryExecutor.execute(query, variables) + assertThat(executionResult.errors).isNotEmpty() + } + + @SpringBootConfiguration(proxyBeanMethods = false) + @SuppressWarnings("unused") + open class LocalApp { + + @DgsComponent + class ExampleImplementation { + + @DgsTypeDefinitionRegistry + fun typeDefinitionRegistry(): TypeDefinitionRegistry { + val schemaParser = SchemaParser() + + val gqlSchema = """ + | type Mutation { + | createPost(createPostInput: CreatePostInput!): String! + | } + | + | input CreatePostInput { + | title: String! @Size(min:5, max:50) + | content: String! + | } + | + | directive @Size(min : Int = 0, max : Int = 2147483647, message : String = "graphql.validation.Size.message") + | on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION + """.trimMargin() + return schemaParser.parse(gqlSchema) + } + + @DgsMutation + fun createPost(@InputArgument createPostInput: CreatePostInput): String { + println(createPostInput) + return UUID.randomUUID().toString() + } + } + + data class CreatePostInput(val title: String, val content: String) + } +} diff --git a/graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfigurationTests.kt b/graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfigurationTests.kt new file mode 100644 index 0000000000..9a09a46e93 --- /dev/null +++ b/graphql-dgs-extended-validation/src/test/kotlin/com/netflix/graphql/dgs/autoconfig/DgsExtendedValidationAutoConfigurationTests.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2021 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.graphql.dgs.autoconfig + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.boot.autoconfigure.AutoConfigurations +import org.springframework.boot.test.context.runner.ApplicationContextRunner + +internal class DgsExtendedValidationAutoConfigurationTests { + + private val context = + ApplicationContextRunner().withConfiguration( + AutoConfigurations.of(DgsExtendedValidationAutoConfiguration::class.java) + ) + + @Test + fun `BeanValidation Autoconfiguration elements are available by default`() { + context.run { context -> + assertThat(context) + .hasSingleBean(DgsExtendedValidationAutoConfiguration::class.java) + } + } +} diff --git a/graphql-dgs-platform/build.gradle.kts b/graphql-dgs-platform/build.gradle.kts index 7d607f0733..677f49b343 100644 --- a/graphql-dgs-platform/build.gradle.kts +++ b/graphql-dgs-platform/build.gradle.kts @@ -51,6 +51,9 @@ dependencies { api("com.graphql-java:graphql-java-extended-scalars") { version { require(Versions.GRAPHQL_JAVA_EXTENDED_SCALARS) } } + api("com.graphql-java:graphql-java-extended-validation") { + version { require(Versions.GRAPHQL_JAVA_EXTENDED_VALIDATION) } + } api("com.apollographql.federation:federation-graphql-java-support") { version { require(Versions.GRAPHQL_JAVA_FEDERATION) } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 59dbe31515..0eada0be76 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,6 +33,7 @@ include("graphql-dgs-spring-boot-micrometer") include("graphql-dgs-platform") include("graphql-dgs-platform-dependencies") include("graphql-dgs-extended-scalars") +include("graphql-dgs-extended-validation") include("graphql-dgs-spring-webflux-autoconfigure") include("graphql-dgs-reactive") include("graphql-dgs-webflux-starter")