-
Notifications
You must be signed in to change notification settings - Fork 48
server_migrate_1 x_to_2 x
- Introduction
-
Changes that may impact the existing implementations
- A word on Spring dependencies
- Compatibility with Spring 3
- Mandatory values for these plugin parameters: copyRuntimeSources, generateBatchLoaderEnvironment, generateDeprecatedRequestResponse and skipGenerationIfSchemaHasNotChanged
- separateUtilityClasses default value is now true
- Change your plugin from dependencies to runtime
- Gradle plugin
- Local path of the server endpoint
- Exception management:
- Support of WebSocket (mandatory for subscriptions)
- Other changes, for information
This page describe how to migrate a server implementation from a 1.x version to the last 2.x version.
If you're looking for a migration of the client implementation, please check the Client migration from 1.x to 2.x
The 2.x version is based on spring-graphql. Spring and spring-graphql are responsible for the whole transport part. The first versions are a mostly a port to use spring-graphql, with the lower impact possible on your exiting code.
As the generated code is based on spring-graphql, spring dependencies are mandatory. spring-graphql doesn't choose between spring-mvc and spring-WebFlux. But the implementation that is done, based on spring-graphql, must choose between these two.
The generated code is based on Spring mvc.
As a consequence, in 2.x, the following dependencies are not needed by the generated code:
- activation and spring-boot-starter: they are no more directly needd.
- graphql-java-spring-mvc (the applications are now web flux apps)
- spring-boot-starter-websocket (the Web Socket protocol is managed directly by
spring-boot-starter-graphql
)
The generated code is compatible with Spring 3. If you use the generateJPAAnnotation plugin parameter with Spring 3, you must set the useJakartaEE9 plugin parameter to true.
It was planned to force some plugin parameters to specific values. But this would have to much impact in existing code. So only the default value changed: new users will have a better code generation. "Old" users can keep the behavior they had, to avoid any code modification.
The recommendation is to follow these default value. But you can force these parameters to their previous value, if it has too much impact on your code.
The default value was true. It is now false.
- If copyRuntimeSources=true, the runtime is copied along with the generated code. The project configuration (pom.xml or build.gradle) must contain the
com.graphql-java-generator:graphql-java-dependencies
dependency, with the same version as the GraphQL plugin - If copyRuntimeSources=false, the runtime is NOT copied along with the generated code. The project configuration (pom.xml or build.gradle) must contain the
com.graphql-java-generator:graphql-java-runtime
dependency, with the same version as the GraphQL plugin
It defines if the environment
parameter is added to the batchLoader()
methods of the generated DataFetchersDelegateXxxx
interfaces. This environment
parameter allows to get information from the GraphQL context.
Here is a sample of such a method:
@Override
public List<AllFieldCasesWithIdSubtype> batchLoader(List<UUID> keys, BatchLoaderEnvironment environment) {
List<AllFieldCasesWithIdSubtype> list = new ArrayList<>(keys.size());
for (UUID id : keys) {
// Let's manage the uppercase parameter, that was associated with each key (and accessible through the environment)
Boolean uppercase = (Boolean) environment.getKeyContexts().get(id);
if (uppercase != null && uppercase) {
item.setName(item.getName().toUpperCase());
}
}
return list;
}
This parameter separates the utility classes generates by the plugin, from the generated classes that match the GraphQL schema (POJO...). This allows a better code structure, and may avoid some class name conflict. But changing this may have impact on existing code.
So, in 2.x versions:
- Its default value changed from false to true
- It is recommended to accept this default value, and adapt your code, as this separates the generated code that maps the GraphQL schema from the utility code that helps to start the server or execute the requests.
- You can define its value to false, to avoid impact on your code.
A note about the copyRuntimeSources
plugin parameter. If its previous value was unset, or set to true, then you must change your project dependency from dependencies
to runtime
. That is: change graphql-java-server-dependencies:pom
(or graphql-java-client-dependencies:pom
) to graphql-java-server-runtime:jar
(or graphql-java-server-runtime:jar
).
For instance, if you're using the plugin for a server, you must change:
<dependency>
<groupId>com.graphql-java-generator</groupId>
<artifactId>graphql-java-server-dependencies</artifactId>
<version>Plugin's version</version>
<type>pom</type>
</dependency>
to this:
<dependency>
<groupId>com.graphql-java-generator</groupId>
<artifactId>graphql-java-server-runtime</artifactId>
<version>Plugin's version</version>
</dependency>
That is: change dependencies
to runtime
, and remove <type>pom</type>
.
For Gradle, if you're using the plugin for a server, you must change:
implementation "com.graphql-java-generator:graphql-java-server-dependencies:${project.pluginRuntimeVersion}"
to this:
implementation "com.graphql-java-generator:graphql-java-server-runtime:${project.pluginRuntimeVersion}"
The default value for the copyRuntimeSources
is false since 2.0. This implies to add the graphql-java-server-runtime:jar
dependency to the project, that in turn implies other dependencies.
Thus, when using the Task/Goal generatePojo
, it is recommended to set copyRuntimeSources
to true. This avoid to add this runtime dependency.
The id changed from com.graphql_java_generator.graphql-gradle-plugin
to com.graphql-java-generator.graphql-gradle-plugin
So the plugins section of the build.gradle is now:
plugins {
// Starting from 2.0RC1, the top level domain changed from "com.graphql_java_generator" to "com.graphql-java-generator"
id "com.graphql-java-generator.graphql-gradle-plugin" version "${graphQLPluginVersion}"
...
}
To run the project from your IDE, you must add the generated source folder and (which is new to 2.x version) the generated resources folder, like this:
sourceSets.main.java.srcDirs += '/build/generated/sources/graphqlGradlePlugin'
sourceSets.main.resources.srcDirs += '/build/generated/resources/graphqlGradlePlugin'
The GraphQL plugin is compiled with Spring Boot 2.7. When the build declared other plugins, and these plugins use Spring dependencies, there may be dependencies 'contentions'.
The error you could encounter are typically:
- ClassNotFound Error for the
org.springframework.core.NestedIOException
class - Issues when searching for the
com.graphql-java-generator:graphql-maven-plugin-logic
dependency
To solve this, you have to update these dependencies, like this buildscript block:
// The GraphQL plugin is compiled with Spring Boot 2.7.
// If you want to use it with Spring Boot 3.x, you have to update these dependencies, like this buildscript block:
buildscript {
repositories {
// The GraphQL plugin depends on libraries that are available with maven
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-starter-graphql:${springBootVersion}"
}
}
In 1.x versions, the plugin allows to define the GraphQL endpoint's path with the graphql.url
entry in the Spring configuration file (application.yml or application.properties)
For servers only, in 2.x releases, this configuration is manager by spring. So the relevant configuration entry becomes spring.graphql.path
in the Spring configuration file. For instance, for an application.properties file:
spring.graphql.path=/another-graphql-endpoint-path
In both 1.x and 2.x releases, the default value is /graphql
Like stated in the spring-graphql project, you can register a DataFetcherExceptionResolverAdapter
that allows proper Exception
management in your GraphQL server. There is a sample in the provided graphql-maven-plugin-samples-allGraphQLCases-server
sample module. You just have to create a subclass of DataFetcherExceptionResolverAdapter
, and override one of the resolveToSingleError
or resolveToMultipleErrors
methods.
Don't forget to add the @Component annotation, to register it.
It is undocumented, but the same mecanism exists for subscriptions exceptions. The class to override is SubscriptionExceptionResolverAdapter
.
The web socket transport is mandatory for subscription. To allow it, a line like this must be added in the application.properties
(or application.yml
) file:
spring.graphql.websocket.path=/graphql
For spring-mvc
, you also need add this dependency to your pom or gradle file:
<!-- Mandatory to enable Web Sockets for Spring-mvc application (mandatory for subscription) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
The schema files are copied to the default spring-graphql folder (that is: the ./graphql folder in the classpath), as this is the default path wher spring-graphql looks for the GraphQL schema file.
RSocket is also supported (see the spring-graphql doc for more information on how to do this)
The main change between the original graphql-java implementation and the Spring logic is the way to wire the Data Fetchers to the GraphQL engine.
- In 1.x branch (with graphql-java), this was done in the generated
GraphQLWiring
class. It used to wire the code for custom scalars and all GraphQL type, unions... Then, theGraphQLDataFetchers
class would wire eachDataFetcherDelegateXxxx
method to the relevant non-scalar field. - spring-graphql uses a different logic:
* The
GraphQLWiring
spring component still exists. But it only wires the custom scalar implementations. The custom scalars to use are declared in the plugin configuration, that in the pom.xml or build.gradle file, like in 1.x releases. * The Controllers: GraphQL web applications must declare a Controller for each GraphQL object, union... This is done by classesXxxxController
that are generated by the plugin. These Controllers are responsible for managing each non-scalar field. * To keep compatibility with code written for 1.x releases of the plugin, the plugin generates theseXxxxController
classes. They are responsible for calling theDataFetchersDelegateXxxx
components (including the BatchLoaders), and then reuse the code written for the 1.x release * It is planned to be able to override the default generated Controllers
In 2.x, it is no more possible to override the GraphQLDataFetchers
spring component.
With spring-graphql, the wiring between the GraphQL requests and the server code is done in the Spring Controllers. It is planned to be able to override theses Controllers.
It is possible to define a DataFetcherExceptionResolver
. It is a custom Spring component that allows to manage the Exceptions thrown by the application, and define which ones must be sent as GraphQL Errors in the GraphQL response.
The default behavior is to mask them into a generic server error.
You'll find a sample in the graphql-maven-plugin-samples-allGraphQLCases-server
module of the 2.x branch. The org.allGraphQLCases.server.config.MyDataFetcherExceptionResolverAdapter
checks if the thrown exception is an instance of GraphQlException
, that is an Exception defined in this project. If it is the case, then it either maps to a new GraphQLError
, or to the actual thrown exception (that implements GraphQLError
).
GraphiQL
is available in spring-graphql. It is inactive by default.
It can be enabled with the spring.graphql.graphiql.enabled
property, to define in the spring configuration file (application.properties or application.yml). It is then available at this path: /graphiql
.
So there is no more need of the com.graphql-java-kickstart:graphiql-spring-boot-starter dependency.
The spring.graphql.schema.printer.enabled
property allows to expose the schema file in text format at /graphql/schema
, to define in the spring configuration file (application.properties or application.yml).
The Batch Loader is the capacity to use that is a very important optimization, on server side. You'll find the details in the java dataloader github page and in the graphql-java site.
The plugin doc for this subject is available in this wiki. Whether you use the 1.x and 2.x version of the plugin, your code implementation is the same.
What's change here is the way the plugin wires the Batch Loader method. With spring-graphql, the Batch Loader method are registered in a Spring BatchLoaderRegistry
, within the constructor of the generated Controller, when needed. You'll find samples of that in the code generated for the graphql-maven-plugin-samples-Forum-server
sample, for instance the TopicController
.
Creating a first app (non spring)
Connect to more than one GraphQL servers
Easily execute GraphQL requests with GraphQL Repositories
Access to an OAuth2 GraphQL server
How to personalize the client app
Howto personalize the generated code
Client migration from 1.x to 2.x
Implement an OAuth2 GraphQL server
Howto personalize the generated code
Server migration from 1.x to 2.x