-
Notifications
You must be signed in to change notification settings - Fork 48
client_more_than_one_graphql_servers
Starting with release 1.17.3, the generated code can attack as many GraphQL servers as you want. Previous releases could be configured to connect to only one GraphQL server.
This comes with little impact on the configuration. You'll find all the info on this page.
In order to be able to attack more several GraphQL servers, you must generate the code for each of them. So the plugin must be executed once for each GraphQL schema. The reasons for that are:
- Some utilities classes are generated, with the same name, but a different content for each GraphQL schema.
- The Spring name must be generated for each GraphQL server and GraphQL schema
- Important notice: to distinguish the Spring beans of each schema, you MUST use the
springBeanSuffix
plugin parameter with a different value for each schema (see below for more information)
- Important notice: to distinguish the Spring beans of each schema, you MUST use the
You can find a sample for that in the project:
- For Maven: in the allGraphQLCases provided sample
- For Gradle: in the allGraphQLCases provided sample
Here is an extract of the pom.xml file (for Maven), that describes this:
...
<build>
<plugins>
<plugin>
<groupId>com.graphql-java-generator</groupId>
<artifactId>graphql-maven-plugin</artifactId>
<executions>
<execution>
<id>graphql-schema1</id>
<goals>
<goal>generateClientCode</goal>
</goals>
<configuration>
.. You can let the configuration for the first GraphQL schema unchanged
<!-- But it's a good idea to have a specific prefix, still -->
<springBeanSuffix>Schema1</springBeanSuffix>
</configuration>
</execution>
<execution>
<id>graphql-schema2</id>
<goals>
<goal>generateClientCode</goal>
</goals>
<configuration>
<!-- You must define a specific target for the generated sources for at least all GraphQL schemas but one -->
<targetSourceFolder>${basedir}/target/generated-sources/graphql-maven-plugin2</targetSourceFolder>
<!-- You must define a suffix different for each GraphQL schemas -->
<springBeanSuffix>Schema2</springBeanSuffix>
.. Then all plugin parameters, as usual, for this GraphQL schema
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
TODO: add a maven sample
Of course, you have to provide the URL for each GraphQL server.
The property name for that is: graphql.endpointXxxx.url
, where Xxxx
is the value of the springBeanSuffix
plugin parameter (as defined in your pom.xml or build.gradle).
Typically, you'll put these lines in your application.properties
file:
graphql.endpointAllGraphQLCases.url = http://localhost:8180/my/updated/graphql/path
graphql.endpointForum.url = http://localhost:8182/graphql
...
It's essentially the same as with one unique GraphQL schema: you Spring Configuration class must scan:
- Your current package (or any root package from which Spring will find your Spring beans)
- The plugin runtime
- Each target package for each GraphQL schema.
In the allGraphQLCases provided sample, you'll find the Main class:
@SuppressWarnings("deprecation")
@SpringBootApplication(scanBasePackageClasses = { Main.class, GraphQLConfiguration.class, MyQueryTypeExecutor.class,
QueryExecutor.class })
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@EnableGraphQLRepositories({ "org.allGraphQLCases.demo.impl", "org.allGraphQLCases.subscription.graphqlrepository" })
public class Main implements CommandLineRunner {
...
}
What's noticeable here is:
-
[VERY IMPORTANT] The
@SpringBootApplication
annotation specifies these packages to scan. This must include the query executors that has been generated for each schema. In the above sample, there is:- Main's package (the application one)
- GraphQLConfiguration's package (the runtime)
- One QueryExecutor for each generated schema :
- MyQueryTypeExecutor's package (the allGraphQLCases GraphQL schema)
- QueryExecutor's package (the forum GraphQL schema)
- No MutationExecutor or SubscriptionExecutor: only one class per generated schema
-
@EnableAutoConfiguration(exclude
avoids to add Spring Data autoconfiguration stuff (Hibernate, JPA...) - The
@EnableGraphQLRepositories
allows to use the [GraphQL Repositories|client_graphql_repository] defined in these packages
The Spring bean that are specific to each GraphQL schema are configured in the xxx.util.SpringConfigurationXxx package, where Xxx is the springBeanSuffix
defined in the pom.xml or in the build.gradle file.
You can override all these beans, for your needs: define a bean of the same and type, and mark it as @Primary
. Your bean will replace the default provided one.
These beans are:
| String graphqlEndpointForumUrl
| The URL for this GraphQL server |
| WebClient webClientForum
| The WebClient: you can define your own WebSocketClient with specific properties, if needed |
| WebSocketClient webSocketClientForum
| The WebSocketClient: you can define your own WebSocketClient with specific properties, if needed |
| OAuthTokenExtractor oAuthTokenExtractorForum
| (mostly internal: a tool that extracts the OAuth token to reuse it in WebSocket) |
| QueryExecutor queryExecutorForum
| The instance that will execute requests for this GraphQL schema |
| GraphQLConfiguration graphQLConfigurationForum
| (mostly internal to the plugin, subjet to changes) |
To activate OAuth in a Spring app, you just have to provide a ServerOAuth2AuthorizedClientExchangeFilterFunction
bean.
The issue here, is that the OAuth configuration will vary, depending on the GraphQL server. And some may be protected by OAuth, and others no.
If at least one of the GraphQL servers that you attack is protected by OAuth, you MUST provide a ServerOAuth2AuthorizedClientExchangeFilterFunction
for each server:
- Either with the OAuth configuration for this server
- Or null if this server isn't protected by OAuth.
The name of this bean MUST be: serverOAuth2AuthorizedClientExchangeFilterFunctionXxxx
, where Xxx is the springBeanSuffix
defined in the pom.xml or in the build.gradle file.
For instance, in the allGraphQLCases provided sample, you'll find the beans definition in the Main class:
...
@Bean
ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunctionAllGraphQLCases(
ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("provider_test");
return oauth;
}
@Bean
ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunctionForum(
ReactiveClientRegistrationRepository clientRegistrations) {
return null;
}
...
As you can see, the AllGraphQLCases
server is protected by OAuth, and the Forum
one isn't.
In this case, two additional rules apply:
- One GraphQL Repository may contain requests (queries, mutations and/or subscriptions) based on only one unique GraphQL schema
- The
QueryExecutor
of this GraphQL schema must be provided in thequeryExecutor
parameter of theGraphQLRepository
java annotation
Here is a sample:
@GraphQLRepository(queryExecutor = MyQueryTypeExecutor.class)
public interface PartialRequestGraphQLRepository extends PartialQueries {
... Your Request definitions go here
}
As MyQueryTypeExecutor
is the query executor for the allGraphQLCases schema, all queries, mutations and/or subscriptions of this GraphQL Repositories must be based on this GraphQL schema. It's name this way, as the Query type's name in this GraphQL schema is MyQueryType
.
The default name for a Query type is actually Query
. In this case, the query executor is named QueryExecutor
.
With non-Spring application, as it's up to you to build the GraphQLConfiguration
, or the query, mutation and subscription classes, you should almost no difference.
The main thing is to generate the code: the plugin must be executed once per GraphQL schema. And each execution must have its own target for the generated classes, as some utilities classes are generated, with the same name, but a different content for each GraphQL schema.
The sample for the Spring Application, here above, are correct also for non-Spring apps. The only difference is that the springBeanSuffix
plugin parameter is useless for non-Spring application.
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