Skip to content

server_faq

etienne-sf edited this page Aug 28, 2024 · 15 revisions

Questions about the server configuration

HowTo to change the server port and path

The server is a Spring Boot app or servlet. It is configured through one of the application.properties or the application.yml files. It should be available in the root of the classpath, so you should provide is in the project's src/main/resources folder.

The below sample is based on the allGraphQLCases-server, available as a sample in the Maven and Gradle projects:

# Changing the port for the GraphQL server
server:
  port: 8180


# Changing the server path
graphql:
  url: /my/updated/graphql/path

HowTo configure OAuth2 for a GraphQL server

Everything is explained in the server OAuth2 page

HowTo configure Spring Security for a GraphQL server

You can find a sample, with the OAuth2 configuration, that includes configuring Spring Security beans.

Personalize your GraphQL server

Change the generated code (custom templates)

The generated code is created from Velocity templates. You can override any of these templates, according to your needs.

You'll find the needed info on the Custom Templates page.

Override the type wiring and/or the DataFetcher definitions

A key point of the GraphQL server behavior is the link between the GraphQL schema and the server code. This link is defined in the type wiring, and this type wiring is coded in the generated GraphQLWiring class. In this class, you'll find the buildWiring() method, that defines the wiring for each type, custom scalar, interface and union defined in the GraphQL schema. The wiring for each is defined in a dedicated method, as you can see in the below extract of this generated code:

@Component
public class GraphQLWiring {

	@Autowired
	protected GraphQLDataFetchers graphQLDataFetchers;

	protected RuntimeWiring buildWiring() {
		return RuntimeWiring.newRuntimeWiring()
			//
			// Wiring every custom scalar definitions
			.scalar(com.graphql_java_generator.customscalars.GraphQLScalarTypeDate.Date)
...
			// Wiring every GraphQL type
			.type("MyQueryType", typeWiring -> addWiringForMyQueryType(typeWiring))
			.type("AnotherMutationType", typeWiring -> addWiringForAnotherMutationType(typeWiring))
			.type("TheSubscriptionType", typeWiring -> addWiringForTheSubscriptionType(typeWiring))
			.type("AllFieldCases", typeWiring -> addWiringForAllFieldCases(typeWiring))
...
			.build();
	} // buildWiring()


	// Declares a DataFetcher for each 
	protected TypeRuntimeWiring.Builder addWiringForMyQueryType(TypeRuntimeWiring.Builder typeWiring) {
		typeWiring.dataFetcher("withoutParameters", graphQLDataFetchers.dataFetchersDelegateMyQueryTypeWithoutParameters());
		typeWiring.dataFetcher("withOneOptionalParam", graphQLDataFetchers.dataFetchersDelegateMyQueryTypeWithOneOptionalParam());
...
		return typeWiring;
	}
...
}

Since version 1.12.4, you can override:

  1. The whole wiring (by overriding the buildWiring()) method of the GraphQLWiring class
  2. The wiring for one type, by overriding one of the addWiringForXxxx(TypeRuntimeWiring.Builder) method of the GraphQLWiring class (where Xxx is the name for the GraphQL object)
  3. The dataFetcher for one field of one object, by overriding just one method `GraphQLDataFetchers``class (see below)

For points 1 and 2, see just below. For point 3, see in the paragraph below (Override the DataFetchers)

To override the GraphQLWiring class, you'll just have to define a Spring Component, that inherits from the GraphQLWiring class. To do this:

  • Create a class in the package where the GraphQL classes is declared, or one of its subpackages, so that Spring can find it
    • It's the package you declare in the packageName plugin parameter of your pom or build.gradle file. If you didn't declare this, the package is the default one, that is: com.generated.graphql
  • Give it another name, like CustomGraphQLWiring
  • Make it inherit from the GraphQLWiring class. This is mandatory, so that it is recognized and used. This also allows you to benefit from the generated code. You may then override only part of the wiring.
  • Mark it as Spring bean, with the @Component Spring annotation
  • Mark it with the @Primary annotation, so that it overrides the one defined in the generated code

Here is a sample, extracted from the provided Forum sample. This sample overrides the GraphQLWiring class, with the CustomGraphQLWiring.

Here is the content of this class:

@Component
@Primary
public class CustomGraphQLWiring extends GraphQLWiring {

	@Override
	protected TypeRuntimeWiring.Builder addWiringForSubscription(TypeRuntimeWiring.Builder typeWiring) {
		typeWiring.dataFetcher("subscribeToNewPost",
				graphQLDataFetchers.dataFetchersDelegateSubscriptionSubscribeToNewPost());
		return typeWiring;
	}

}

Override the DataFetchers or Spring Controllers (= change the way the data is fetched for one field of one object)

Versions 1.x (no Spring Controllers)

As defined on this page, graphql-java uses data fetchers (also named resolvers) to fetch data. There is one data fetcher:

  • For each field of your query, mutation and subscription classes
  • For each field of your GraphQL type or interface that is not a scalar.

As specified in the server page, it's up to you to implement these data fetchers. So the generated code generates interfaces named DataFetcherDelegate, that define the expected method for each data fetcher, that you should implement. This should work for most GraphQL server implementations.

But it may happen that you're not happy with these methods.

So, since version 1.12.4, all the data fetchers for your server are defined in the generated GraphQLDataFetchers class. You can override this class, and provide an alternate data fetcher for any data fetcher.

To override the GraphQLDataFetchers class, you'll just have to define a Spring Component, that inherits from the GraphQLWiring class. To do this:

  • Create a class in the package where the GraphQL classes is declared, or one of its subpackages, so that Spring can find it
    • It's the package you declare in the packageName plugin parameter of your pom or build.gradle file. If you didn't declare this, the package is the default one, that is: com.generated.graphql
  • Give it another name, like CustomGraphQLDataFetchers
  • Make it inherit from the GraphQLDataFetchers class. This is mandatory, so that it is recognized and used. This also allows you to benefit from the generated code. You may then override only part of the wiring.
  • Mark it as Spring bean, with the @Component Spring annotation
  • Mark it with the @Primary annotation, so that it overrides the one defined in the generated code

Here is a sample, extracted from the provided Forum sample. This sample overrides the GraphQLDataFetchers class, with the CustomGraphQLDataFetchers.

Here is the content of this class:

@Component("overridenGraphQLDataFetchers")
@Primary
public class CustomGraphQLDataFetchers extends org.forum.server.graphql.GraphQLDataFetchers {

	@Override
	public DataFetcher<Board> dataFetchersDelegateMutationCreateBoard() {
		return dataFetchingEnvironment -> {
			String name = (String) graphqlUtils.getArgument(dataFetchingEnvironment.getArgument("name"),
					"${argument.type.graphQLTypeSimpleName}", "java.lang.Long", String.class);
			Boolean publiclyAvailable = (Boolean) graphqlUtils.getArgument(
					dataFetchingEnvironment.getArgument("publiclyAvailable"), "${argument.type.graphQLTypeSimpleName}",
					"java.lang.Long", Boolean.class);

			Board ret = null;
			try {
				// HERE IS WHAT's CHANGED IN THIS OVERRIDEN VERSION:
				// We add " (Overridden DataFetcher)" to the name
				ret = dataFetchersDelegateMutation.createBoard(dataFetchingEnvironment,
						name + " (Overridden DataFetcher)", publiclyAvailable);
			} catch (NoSuchElementException e) {
				// There was no items in the Optional
			}

			if (ret != null)
				logger.debug("createBoard (Overridden DataFetcher): 1 result found");
			else
				logger.debug("createBoard (Overridden DataFetcher): no result found");

			return ret;
		};
	}
}

Versions 2.x

In version 2.x, it's possible to override the default GraphQL Spring Mappings.

The [ignoredSpringMappings](https://graphql-maven-plugin-project.graphql-java-generator.com/graphql-maven-plugin/plugin-info.html) plugin parameters allow to declare a list of GraphQL mappings that will be ignored by the plugin. These ignored mappings can then be defined by the specific implementation.

The other way to it is to create a spring GraphQL Controller, that overrides the controller generated by the plugin. But this may lead to this error: Ambiguous mapping. Cannot map 'xxxController' method [...] to 'Type.field': there is already 'yyy' bean method [...] mapped.

The parameter contains a list of:

  • GraphQL type name: The full controller class for this type is ignored, and won't be generated
  • GraphQL type's field name: The method in the controller of this type, for this field, is ignored, and won't be generated. The field must be written like this: {type name}.{field name}

The accepted separators for the values are: comma, space, carriage return, end of line, space, tabulation. At least one separator must exist between two values in the list. Here is a sample:

          <ignoredSpringMappings>Type1, Type2.field1
          	Type3
          	Type4.field2
          </ignoredSpringMappings>

For field mapping, there must be no separator other than '.' between the type name and the field name. For instance, the following type declaration are invalid: 'type .field', 'type. field'

HowTo provide your GraphQL ExecutionInputCustomizer, ExecutionResultHandler, GraphQLInvocation, GraphQLController and JacksonJsonSerializer

The plugin uses a clone of the graphql-java-spring project. We provided PR for this project, but as it seems to not be maintained, we cloned it into the plugin project, until the PR are accepted and a new version is published.

As defined in the graphql-java-spring project, you can override the main GraphQL component, that is:

To replace any of these implementations, you just have to provide a Spring Bean that implements the same interface, like this:

  • Create a class in the package where the GraphQL classes is declared, or one of its subpackages, so that Spring can find it
    • It's the package you declare in the packageName plugin parameter of your pom or build.gradle file. If you didn't declare this, the package is the default one, that is: com.generated.graphql
  • Give it another name, like CustomXxxx, where Xxx is the name of the interface you implement
  • Make it implement the interface of the component you want to override (or inherit from it)
  • Mark it as Spring bean, with the @Component Spring annotation
  • Mark it with the @Primary annotation, so that it overrides the one defined in the generated code

Errors during execution

WebSocketClientHandshakeException: Invalid handshake response getStatus: 405

It means that the server doesn't properly manage web sockets.

Please read the Subscription page.

For 2.x versions, please read the Server migration from 1.x to 2.x page, especially the Support of WebSocket (mandatory for subscriptions) part.

Clone this wiki locally