Skip to content

Commit 0e351d0

Browse files
authored
Add a maven plugin to generate the augmented schema (#228)
This will allow the use of a type save graphql API.
1 parent b146294 commit 0e351d0

File tree

8 files changed

+258
-28
lines changed

8 files changed

+258
-28
lines changed

examples/dgs-spring-boot/pom.xml

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,27 +101,54 @@
101101
<groupId>org.springframework.boot</groupId>
102102
<artifactId>spring-boot-maven-plugin</artifactId>
103103
</plugin>
104-
104+
<plugin>
105+
<groupId>org.neo4j</groupId>
106+
<artifactId>neo4j-graphql-augmented-schema-generator-maven-plugin</artifactId>
107+
<version>1.3.1-SNAPSHOT</version>
108+
<executions>
109+
<execution>
110+
<goals>
111+
<goal>generate-schema</goal>
112+
</goals>
113+
<configuration>
114+
<schemaConfig>
115+
<pluralizeFields>true</pluralizeFields>
116+
<useWhereFilter>true</useWhereFilter>
117+
<queryOptionStyle>INPUT_TYPE</queryOptionStyle>
118+
<mutation>
119+
<enabled>false</enabled>
120+
</mutation>
121+
</schemaConfig>
122+
<outputDirectory>${project.build.directory}/augmented-schema</outputDirectory>
123+
<fileset>
124+
<directory>${project.basedir}/src/main/resources</directory>
125+
<include>*.graphql</include>
126+
</fileset>
127+
</configuration>
128+
</execution>
129+
</executions>
130+
</plugin>
105131
<plugin>
106132
<groupId>io.github.deweyjose</groupId>
107133
<artifactId>graphqlcodegen-maven-plugin</artifactId>
108-
<version>1.8</version>
134+
<version>1.10</version>
109135
<executions>
110136
<execution>
111137
<goals>
112138
<goal>generate</goal>
113139
</goals>
140+
<configuration>
141+
<schemaPaths>
142+
<param>src/main/resources/schema/schema.graphqls</param>
143+
<param>target/augmented-schema/neo4j.graphql</param>
144+
</schemaPaths>
145+
<language>kotlin</language>
146+
<generateClient>true</generateClient>
147+
<generateDataTypes>true</generateDataTypes>
148+
<packageName>org.neo4j.graphql.examples.dgsspringboot.types</packageName>
149+
</configuration>
114150
</execution>
115151
</executions>
116-
<configuration>
117-
<schemaPaths>
118-
<param>src/main/resources/schema/schema.graphqls</param>
119-
</schemaPaths>
120-
<generateClient>true</generateClient>
121-
<generateInterfaces>true</generateInterfaces>
122-
<generateDataTypes>true</generateDataTypes>
123-
<packageName>org.neo4j.graphql.examples.dgsspringboot.types</packageName>
124-
</configuration>
125152
</plugin>
126153
<plugin>
127154
<groupId>org.codehaus.mojo</groupId>

examples/dgs-spring-boot/readme.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ With This in place you can
2525
```graphql
2626
query{
2727
other
28-
movie (first: 3){
28+
movies (options: {limit: 3}){
2929
title
3030
bar
3131
javaData {
@@ -34,3 +34,7 @@ query{
3434
}
3535
}
3636
```
37+
38+
=== What's next
39+
40+
Take a look into the link:src/test/kotlin/org/neo4j/graphql/examples/dgsspringboot/datafetcher/AdditionalDataFetcherTest.kt[Test-Case] to see, how the generated POJOs of your augmented schema can be used to request data

examples/dgs-spring-boot/src/main/kotlin/org/neo4j/graphql/examples/dgsspringboot/config/GraphQLConfiguration.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import graphql.schema.idl.SchemaParser
1010
import graphql.schema.idl.TypeDefinitionRegistry
1111
import org.neo4j.graphql.DataFetchingInterceptor
1212
import org.neo4j.graphql.SchemaBuilder
13+
import org.neo4j.graphql.SchemaConfig
1314
import org.springframework.beans.factory.annotation.Autowired
1415
import org.springframework.beans.factory.annotation.Value
1516
import org.springframework.core.io.Resource
@@ -34,7 +35,12 @@ open class GraphQLConfiguration {
3435
fun postConstruct() {
3536
val schema = graphQl.inputStream.bufferedReader().use { it.readText() }
3637
val typeDefinitionRegistry = SchemaParser().parse(schema)
37-
schemaBuilder = SchemaBuilder(typeDefinitionRegistry)
38+
schemaBuilder = SchemaBuilder(typeDefinitionRegistry, SchemaConfig(
39+
pluralizeFields = true,
40+
useWhereFilter = true,
41+
queryOptionStyle = SchemaConfig.InputStyle.INPUT_TYPE,
42+
mutation = SchemaConfig.CRUDConfig(enabled = false))
43+
)
3844
schemaBuilder.augmentTypes()
3945
}
4046

examples/dgs-spring-boot/src/test/kotlin/org/neo4j/graphql/examples/dgsspringboot/datafetcher/AdditionalDataFetcherTest.kt

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package org.neo4j.graphql.examples.dgsspringboot.datafetcher
22

3+
import com.jayway.jsonpath.TypeRef
34
import com.netflix.graphql.dgs.DgsQueryExecutor
5+
import com.netflix.graphql.dgs.client.codegen.GraphQLQueryRequest
6+
import org.assertj.core.api.Assertions
47
import org.junit.jupiter.api.AfterEach
58
import org.junit.jupiter.api.BeforeEach
69
import org.junit.jupiter.api.Test
710
import org.neo4j.driver.Driver
811
import org.neo4j.driver.springframework.boot.autoconfigure.Neo4jDriverProperties
12+
import org.neo4j.graphql.examples.dgsspringboot.types.DgsConstants
13+
import org.neo4j.graphql.examples.dgsspringboot.types.client.MoviesGraphQLQuery
14+
import org.neo4j.graphql.examples.dgsspringboot.types.client.MoviesProjectionRoot
15+
import org.neo4j.graphql.examples.dgsspringboot.types.types.Movie
916
import org.skyscreamer.jsonassert.JSONAssert
1017
import org.springframework.beans.factory.annotation.Autowired
1118
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -47,25 +54,29 @@ internal class AdditionalDataFetcherTest(
4754

4855
@Test
4956
fun testHybridDataFetcher() {
50-
val response = dgsQueryExecutor.executeAndGetDocumentContext("""
51-
query{
52-
other
53-
movie{
54-
title
55-
bar
56-
javaData {
57-
name
58-
}
59-
}
60-
}
61-
""".trimIndent())
57+
58+
val graphQLQueryRequest = GraphQLQueryRequest(
59+
// there is an issue with empty fields of input type (https://github.com/Netflix/dgs-codegen/issues/140)
60+
MoviesGraphQLQuery(),
61+
MoviesProjectionRoot().also { movie ->
62+
movie.title()
63+
movie.bar()
64+
movie.javaData().also { javaData ->
65+
javaData.name()
66+
}
67+
}
68+
)
69+
70+
val request = graphQLQueryRequest.serialize()
71+
Assertions.assertThat(request).isEqualTo("query {movies{ title bar javaData { name } } }")
72+
73+
val response = dgsQueryExecutor.executeAndGetDocumentContext(request)
6274

6375
//language=JSON
6476
JSONAssert.assertEquals("""
6577
{
6678
"data": {
67-
"other": "other",
68-
"movie": [
79+
"movies": [
6980
{
7081
"title": "The Matrix",
7182
"bar": "foo",
@@ -97,6 +108,9 @@ internal class AdditionalDataFetcherTest(
97108
}
98109
}
99110
""".trimIndent(), response.jsonString(), true)
111+
112+
val list = response.read("data.${DgsConstants.QUERY.Movies}", object : TypeRef<List<Movie>>() {})
113+
Assertions.assertThat(list).hasSize(3)
100114
}
101115

102116
@TestConfiguration
@@ -118,6 +132,5 @@ internal class AdditionalDataFetcherTest(
118132
companion object {
119133
@Container
120134
private val neo4jServer = Neo4jContainer<Nothing>("neo4j:4.2.4")
121-
122135
}
123136
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>neo4j-graphql-java-parent</artifactId>
7+
<groupId>org.neo4j</groupId>
8+
<version>1.3.1-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>neo4j-graphql-augmented-schema-generator-maven-plugin</artifactId>
13+
<name>Neo4j GraphQL augmented schema generator Maven Plugin</name>
14+
15+
<packaging>maven-plugin</packaging>
16+
17+
<properties>
18+
<maven.compiler.source>11</maven.compiler.source>
19+
<maven.compiler.target>11</maven.compiler.target>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>org.apache.maven</groupId>
25+
<artifactId>maven-plugin-api</artifactId>
26+
<version>3.6.3</version>
27+
<scope>provided</scope>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.apache.maven.plugin-tools</groupId>
31+
<artifactId>maven-plugin-annotations</artifactId>
32+
<version>3.6.0</version>
33+
<scope>provided</scope>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.apache.maven.shared</groupId>
37+
<artifactId>file-management</artifactId>
38+
<version>3.0.0</version>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>org.neo4j</groupId>
43+
<artifactId>neo4j-graphql-java</artifactId>
44+
<version>1.3.1-SNAPSHOT</version>
45+
</dependency>
46+
</dependencies>
47+
48+
<build>
49+
<plugins>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-plugin-plugin</artifactId>
53+
<version>3.6.0</version>
54+
<executions>
55+
<execution>
56+
<id>default-descriptor</id>
57+
<phase>process-classes</phase>
58+
</execution>
59+
<!-- if you want to generate help goal -->
60+
<execution>
61+
<id>help-goal</id>
62+
<goals>
63+
<goal>helpmojo</goal>
64+
</goals>
65+
</execution>
66+
</executions>
67+
</plugin>
68+
</plugins>
69+
</build>
70+
71+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.neo4j.graphql.augmented_schema_generator.plugin
2+
3+
import graphql.schema.idl.SchemaPrinter
4+
import org.apache.maven.plugin.AbstractMojo
5+
import org.apache.maven.plugin.MojoExecutionException
6+
import org.apache.maven.plugins.annotations.LifecyclePhase
7+
import org.apache.maven.plugins.annotations.Mojo
8+
import org.apache.maven.plugins.annotations.Parameter
9+
import org.apache.maven.shared.model.fileset.FileSet
10+
import org.apache.maven.shared.model.fileset.util.FileSetManager
11+
import org.neo4j.graphql.SchemaBuilder
12+
import org.neo4j.graphql.SchemaConfig
13+
import java.io.File
14+
import java.nio.charset.Charset
15+
import javax.inject.Inject
16+
import kotlin.io.path.ExperimentalPathApi
17+
import kotlin.io.path.readText
18+
19+
/**
20+
* Simple Mojo generating an augmented schema and writes it to the specified outputDirectory
21+
*/
22+
@Mojo(name = "generate-schema", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
23+
class AugmentedSchemaGeneratorMojo : AbstractMojo() {
24+
25+
/**
26+
* The configuration to use to augment a schema
27+
*/
28+
@Parameter
29+
private val schemaConfig: SchemaConfig = SchemaConfig()
30+
31+
32+
/**
33+
* The folder to which the generated augmented schemas are written
34+
*/
35+
@Parameter(required = true)
36+
private lateinit var outputDirectory: File
37+
38+
/**
39+
* A set of schemas to be augmented
40+
*/
41+
@Parameter(required = true)
42+
private lateinit var fileset: FileSet
43+
44+
@Inject
45+
private lateinit var fileSetManager: FileSetManager
46+
47+
@ExperimentalPathApi
48+
@Throws(MojoExecutionException::class)
49+
override fun execute() {
50+
val includedFiles: Array<String> = fileSetManager.getIncludedFiles(fileset)
51+
val schemaPrinter = SchemaPrinter(SchemaPrinter.Options
52+
.defaultOptions()
53+
.includeDirectives(true)
54+
.includeScalarTypes(true)
55+
.includeSchemaDefinition(true)
56+
.includeIntrospectionTypes(false)
57+
)
58+
59+
includedFiles.forEach { file ->
60+
val schemaContent = java.nio.file.Path.of(fileset.directory, file).readText(Charset.defaultCharset())
61+
val schema = SchemaBuilder.buildSchema(schemaContent, schemaConfig)
62+
val augmentedSchema = schemaPrinter.print(schema)
63+
val outputfile = File(outputDirectory, file)
64+
outputfile.parentFile.mkdirs()
65+
outputfile.writeText(augmentedSchema)
66+
log.info("writing augmented schema to $outputfile")
67+
}
68+
}
69+
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
<modules>
3434
<module>core</module>
35+
<module>neo4j-graphql-augmented-schema-generator-maven-plugin</module>
3536
<module>examples</module>
3637
</modules>
3738

readme.adoc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,42 @@ mutation {
721721

722722
You find more examples in the link:core/src/test/resources/augmentation-tests.adoc[Augmentation Tests]
723723
and the link:core/src/test/resources/custom-fields.adoc[Custom queries and mutations Tests]
724+
725+
== Build time schema augmentation
726+
727+
Sometimes you need the possibility to generate the augmented schema at compile time. To achieve this, we provide a maven plugin which can be used as follows:
728+
729+
[source,xml,subs="attributes,verbatim"]
730+
----
731+
<plugin>
732+
<groupId>org.neo4j</groupId>
733+
<artifactId>neo4j-graphql-augmented-schema-generator-maven-plugin</artifactId>
734+
<version>{version}</version>
735+
<executions>
736+
<execution>
737+
<goals>
738+
<goal>generate-schema</goal>
739+
</goals>
740+
<configuration>
741+
<schemaConfig> <!--1-->
742+
<pluralizeFields>true</pluralizeFields>
743+
<useWhereFilter>true</useWhereFilter>
744+
<queryOptionStyle>INPUT_TYPE</queryOptionStyle>
745+
<mutation>
746+
<enabled>false</enabled>
747+
</mutation>
748+
</schemaConfig>
749+
<outputDirectory>${project.build.directory}/augmented-schema</outputDirectory>
750+
<fileset> <!--2-->
751+
<directory>${project.basedir}/src/main/resources</directory>
752+
<include>*.graphql</include>
753+
</fileset>
754+
</configuration>
755+
</execution>
756+
</executions>
757+
</plugin>
758+
----
759+
<1> Use the same configuration as for your SchemaBuilder
760+
<2> Define the source schema for which you want to have an augmented schema generated
761+
762+
Take a look at the link:./examples/dgs-spring-boot/readme.adoc[spring boot dsg] example for a use case of this plugin, where it is used in combination with a code generator to have a type save graphql API

0 commit comments

Comments
 (0)