-
Notifications
You must be signed in to change notification settings - Fork 49
client_migrate_1 x_to_2 x
- Introduction
-
Main changes
- Spring dependencies
- Compatibility with Spring 3
- Impact on plugin parameters: change of some default values
- Change your plugin dependencies from dependencies to runtime
- Task/Goal generatePojo
- Gradle plugin
- Base configuration (GraphQL schema, server url...)
- Spring GraphQlClient
- Support removed for javax.ws.rs.client.Client
- Other changes
- Query and Mutation (choice of the transport protocol)
- Subscription
This page describe how to migrate a client implementation from a 1.x version to the last 2.x version.
If you're looking for a migration of the server implementation, please check the Server 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 allows to easily move from 1.x to 2.x versions.
This project is based in Spring WebFlux.
The generated code is compatible with Spring 3.
If you're using the Gradle plugin you may have to check the configuration to build with Spring Boot 3
If you use the generateJPAAnnotation plugin parameter with Spring 3, you must set the useJakartaEE9 plugin parameter to true.
Gradle mixes dependencies between plugin executions: where everything is fine with Maven, the execution of the Gradle plugin may end with some ClassNotFoundException
errors.
Please go to the Configuration to build with Spring Boot 3 section to solve it.
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.
TODO: change the test code accordingly.
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
The default value changed from true (in 1.x version) to false (since 2.0).
The first versions of the plugin generate classes that are actually useless, and pollute the generated code. The recommended value for this parameter is false.
The main change, then, is that your code will have to use the Executor
s method, like explained in the wiki client page.
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
if you're building your project with Spring Boot 2 and Spring Framework 5 -
com.graphql-java-generator.graphql-gradle-plugin3
if you're building your project with Spring Boot 3 and Spring Framework 6
So the plugins section of the build.gradle is now, for instance:
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}"
...
}
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 errors 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 use the plugin3, like this:
plugins {
id "com.graphql-java-generator.graphql-gradle-plugin3" version "${graphQLPluginVersion}"
...
}
dependencies {
// Use the server runtime ... for the server side :)
implementation "com.graphql-java-generator:graphql-java-server-runtime:${graphQLRuntimeVersion}"
// OR
// Use the client runtime ... for the client side :)
implementation "com.graphql-java-generator:graphql-java-client-runtime:${graphQLRuntimeVersion}"
...
}
See the Gradle change log for the version to use.
(unchanged) The schema file is searched in src/main/resources
. This overrides the schema default location of spring-graphql, which is src/main/resources/graphql
Here are some impact to consider:
- In 1.x releases of the plugin the GraphQL endpoint's path is configured by the
graphql.url
entry in the Spring configuration file (application.yml or application.properties)- [for servers only] In the 2.x releases, this configuration is manager by spring. So the relevant configuration entry is
spring.graphql.path
in the Spring configuration file. Its default value is/graphql
- [for client only] As there seems to be no way to define two GraphQL server urls in Spring GraphQL yet, the configuration entry remains
graphql.endpointXXXXXX.url
, where XXXXXX is the suffix defined in your pom.xml or gradle.plugin (it may be undefined, and is then empty) - Note: take care that Spring's properties ends with path, whereas the client is an url.
- [for servers only] In the 2.x releases, this configuration is manager by spring. So the relevant configuration entry is
- Exception management for Subscription
- It is slightly different, as connection errors are now received by the callback, as the IO are now non blocking.
The GraphQLConfiguration
class has been removed. It was used to manage GraphQL configuration for non Spring apps based on the Jersey http client. The support for these apps has been removed, as the generated code is based on Spring. Non-spring apps are still supported, provided that they are encapsulated in a Spring app, like documented in the non Spring app page.
An impact is the use of the @SpringBootApplication
annotation, on the main app class. The GraphqlClientUtils
should be used instead, along with the QueryExecutor
that must be loaded as Spring Bean, like this:
@SpringBootApplication(scanBasePackageClasses = { SpringMain.class, GraphqlClientUtils.class, QueryExecutor.class })
public class SpringMain {
... Do something that uses GraphQL
}
Behind the query, mutation and subscription executors that are generated by the plugin, all requests are actually executed by a Spring GraphQlClient
bean. The generated autoconfiguration class contains one or two such beans:
- A bean named
httpGraphQlClient
that is used to execute queries and mutations.- The beans uses the generated Spring
WebClient
bean to execute the requests over http.
- The beans uses the generated Spring
- A bean named
webSocketGraphQlClient
(only if subscriptions are defined in the GraphQL schema), that is used to execute subscriptions
Like all the beans defined in the generated Spring auto configuration class, these beans can be overriden in your own Spring configuration. You'll just have to create a bean of the same name and type, and mark is as @Primary
(caution: the generated autoconfiguration class MUST NOT be scanned by your Spring configuration, otherwise it becomes a standard Configuration class, and the @Primary
annotation won't work). This allows to, for instance:
- Define the
CodecCustomizer
- Provide your own
HttpClient
- Add an
ExchangeFilterFunction
, like theServerOAuth2AuthorizedClientExchangeFilterFunction
to manage OAuth on websocket for subscriptions (see below)
The javax.ws.rs.client.Client
is no more accepted. The Spring stack must be used instead.
OAuth is now supported by the standard Spring Boot configuration classes.
You'll still have to declare the oauth provider. For instance, for an application.properties
that contains:
...
# Configuration for OAuth2, for our local OAuth authorization server
spring.security.oauth2.client.registration.provider_test.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.provider_test.client-id=clientId
spring.security.oauth2.client.registration.provider_test.client-secret=secret
...
then you'll have to define these beans in your configuration class:
@Bean
@Primary
ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunction(
ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("provider_test");
return oauth;
}
@Bean
@Primary
public WebClient webClient(String graphqlEndpoint,
CodecCustomizer defaultCodecCustomizer,
@Autowired(required = false) @Qualifier("httpClient") HttpClient httpClient,
@Autowired(required = false) @Qualifier("serverOAuth2AuthorizedClientExchangeFilterFunction") ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunction) {
return WebClient.builder()
.baseUrl(graphqlEndpoint)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultUriVariables(Collections.singletonMap("url", graphqlEndpoint))
.filter(serverOAuth2AuthorizedClientExchangeFilterFunction)
.build();
}
The generated Executors
are Spring beans, and should now be retrieved only as Spring bean, like this:
@Component
public class MyComponent {
@Autowired
QueryExecutor queryExecutor;
public void doSomething(){
List<Character> withoutParameters() = queryExecutor.withoutParameters("{appearsIn name }");
...
}
}
It is used to execute full requests. It is now suffixed by the schema suffix defined in the springBeanSuffix
defined in the plugin configuration, which is an empty string by default.
Prepared full requests can be prepared like this:
@Component
class MySpringComponent {
@Autowired
AnotherMutationTypeExecutor mutationExecutor;
private GraphQLRequest GraphQLRequest;
public MySpringComponent() {
GraphQLRequest = new GraphQLRequest("mutation{createHuman (human: &humanInput) {id name appearsIn friends {id name}}}");
}
void doSomething(Human humanParam) {
Human human = mutationExecutor.exec(GraphQLRequest, "humanInput", humanParam).getCreateHuman();
... Do something useful with human
}
The GraphQLRequestExecutionException
allows to retrieve the errors returned by the GraphQL server through its getErrors()
method.
As spring-graphql encapsulates these errors into the org.springframework.graphql.ResponseError
class, the getErrors()
return type is now List<ResponseError>
.
The new queryMutationExecutionProtocol
plugin parameter allows to choose between http (default) and webSocket.
The SubscriptionClient
now contains only the unsubscribe()
method. The getSession()
(that allows to retrieve the WebSocketSession
has been removed, as all the web socket management is now done by spring-graphql)
The SubscriptionCallback
interface is unchanged. But its onError(Throwable)
method is now called with a GraphQLRequestExecutionException
: its getErrors()
method allows to retrieve the list of errors returned by the GraphQL server.
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