-
Notifications
You must be signed in to change notification settings - Fork 48
server_migrate_1 x_to_2 x
- Introduction
- Changes that impact the existing code
- Other changes
- Other changes, for information
- TODO : re-write this part
- Step to remove the DataFetchers
- Current step
- GraphQLServerMain
- CustomGraphQLController
- RuntimeWiring
- DataLoader
- TypeResolver
Work in progress (2.x is about to be released)
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.
Next versions will allow more control on the spring-graphql part, including overriding the Spring GraphQL controllers.
The dependencies are based on Spring MVC.
TODO :
- 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 servers only] In the 2.x releases, this configuration is manager by spring. So the relevant configuration entry is
TODO Finish here
TODO None of them??
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 default endpoint is /graphql (like before). The way to change it is now the spring.graphql.path
property (in application.properties or application.yml), like this:
spring.graphql.path=/another-graphql-endpoint-path
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
The schema files are copied to the default spring-graphql folder, that is: the ./graphql folder in the classpath
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. This are declared in the plugin configuration, 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 * You can also write the XxxxController yourself (see below). But then, you must write yourself the controllers, and maintain them when the GraphQl schema changes.
- It's no more possible to override the
GraphQLDataFetchers
spring component.- If the default data fetchers doesn't respect your needs, check the Spring Controllers
- Exception may be managed by one or more
DataFetcherExceptionResolver
in a list ofgraphqlGraphQLError
- See sample:
CustomExceptionHandling
and its registration inCustomExceptionHandlingRegistring
- See sample:
-
GraphiQL
is active by default in spring-graphql, at /graphiql. It can be turned off with thespring.graphql.graphiql.enabled
property - The
spring.graphql.schema.printer.enabled
property allows to expose the schema file in text format at/graphql/schema
- Removed these dependencies :
- For server mode:
- 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
)
- For client mode:
- TODO: document it
- For server mode:
If you created a GraphQL server, based on 1.* versions of the plugin, the only link with the plugin's generated code is the DataFetcherDelegate
implementations. You can keep it as it was with 1.* versions of the plugin: it will still work as before.
You can also broke this link, and change your DataFetcherDelegate
implementations to Spring controllers. This allows to use more powerful functionalities.
The steps to do this are:
- TODO: plugin parameter to not generate the dataFetcherDelegate (and the XxxxController classes)
- There is a work for each of your
DataFetcherDelegate
classes:- You should rename it, as the naming convention in spring-graphql is XxxController, where Xxx is the name of the relevant GraphQL type (as defined in your GraphQL schema)
- Mark it with the
@Controller
Spring annotation (otherwise, it is just ignored by Spring) - For
DataFetcherDelegate
classes that are not the Query, Mutation or Subscription one: mark it with either-
@SchemaMapping
(in which case the XxxController naming convention should be obeyed, but you also need to check the@SchemaMapping
on the methods) -
@SchemaMapping(typeName = "Xxx")
where Xxxx is the GraphQL type's name
-
- For classes that contain a
batchLoader
or aunorderedReturnBatchLoader
, you must register a DataLoader- TODO : Document howto register a DataLoader (or to use the
@BatchMapping
Spring annotation)
- TODO : Document howto register a DataLoader (or to use the
- TODO finish here
- Mark all your
TODO: §4.1.1: find schema files
No more bean declaration. This class now only contains the main method.
This class is no longer used (along with all the graphql-java-spring modules)
The existing code generates a GraphQLWiring
class, with various method that could be overriden to change the default runtime wiring.
spring-graphql introduces a new notion: RuntimeWiringConfigurer
. Spring Boot will find all Spring bean that implements the RuntimeWiringConfigurer
interface, and call their configure()
method.
The main update are:
- The
GraphQLWiring
class implements theRuntimeWiringConfigurer
class. - The only use of this class is to declare the scalar implementations.
- DataFetchers are now found by Spring Boot, by scanning the
@Controller
annotation - TODO : and TypeResolvers?
TODO: Check if GraphQLWiring
can be overriden Probably not. So how can one override the default type resolving stuff. (first step: check what was ask on this subject, that is: the reason why this has been structured this way. And does a test exist for this). See CustomGraphQLWiring
TODO explain CustomGraphQLWiring
TODO: finish the job
- Use the @BatchMapping on a
default
interface method - "By default, the field name defaults to the method name, while the type name defaults to the simple class name of the input List element type. Both can be customized through annotation attributes."
- To manage cases where the method name is not the field name (when a field name doesn't respect the java naming convention), then the actual field's name should be written in the @BatchMapping annotation
The ClassNameTypeResolver
is the default TypeResolver
for interfaces and unions. It tries to match the simple class name of the value to a GraphQL Object Type and if it is not successful, it also navigates its super types including base classes and interfaces, looking for a match.
In the 1.* release, the TypeResolver
s are defined in the GraphQLWiring
generated class. This allows to manage GraphQL Object Type names that dosn't match Java naming convention (for instance, when using Java keywords). But this would be quite unlikey to happen.
It works well when the DataFether
s signatures are generated by the code: their return is directly managed by the plugin's code.
On the other side, with spring-graphql, it is possible to creates one's own DataFetcher that may return java datatype that are not match as well with GraphQL Object Type's name. In this case, the Spring Boot implementation would be better.
TODO: one of the above solutions. 2 seems the best one.
TODO: 1) add a parameter to generate them ??
TODO: 2) no more definition of TypeResolver
in the generated code, and add a doc to explain how to do it when it is necessary.
TODO: This allows to entirely remove the GraphQLWiring
class, and so let's the developper free to do what he/she wants there.
TODO: 3) possibly just generate it when the java name is different from the GraphQL Object Type's name (but how to allow the developper to override it?).
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