Skip to content

client_subscription

etienne-sf edited this page Oct 2, 2021 · 23 revisions

Subscription in client mode

The client mode makes it easy for a Java GraphQL client-side application, to execute subscriptions against a GraphQL server. The graphql-maven-plugin generates all the necessary code, so that a Java application can call a GraphQL server by simply calling the relevant Java method.

Since v1.14, subscriptions work with both Partial Request and Full Requests. You'll find the differences between Full and Partial requests on the client FAQ and the client page.

As for queries and mutations, subscription can be executed in two ways:

  • The direct execution: you call the generated method with the GraphQL request (partial or full), and you receive the result into Java objects. This is simpler, but slower: for technical reasons, the plugin has two analyze the content of the request.
    • As Subscription is usually executed once, the direct execution is the recommended way to execute subscriptions.
  • The prepared execution:
    • A GraphQLRequest object is created by the application, if possible at application startup. This allows to analyze the request only once. And it avoids errors during the app execution, as all the GraphQL requests have been checked at startup.
    • Each GraphQL request execution is executed from this object.

Both kinds of requests, and both modes of execution allows to use bind parameters into your query definitions.

How to use subscriptions with the plugin?

First, you'll have to create or get your GraphQL schema. The GraphQL plugin expects a .graphqls file. See the GraphQL schema doc for all the details.

Then, add the plugin to your Maven POM file, as described in the client page.

Full requests

Since v1.14, you can execute subscriptions with full requests. The main advantage is that it allows you to use GraphQL variables.

Here is a sample:

@Component
public class SubscriptionRequests {

	@Autowired
	SubscriptionExecutor subscriptionTypeExecutor;
	
	GraphQLRequest subscriptionRequest;
	
	// Let's prepare the request, once the bean is ready (and the autowired attributes have been set by Spring)
	@PostConstruct
	public void init() {
		subscriptionRequest = subscriptionTypeExecutor.getGraphQLRequest(
				"subscription sub($boardNameParam: String!) {subscribeToNewPost(boardName: $boardNameParam){}}");
				getSubscribeToNewPostGraphQLRequest("{id date author publiclyAvailable title content}");
	}

	public SubscriptionClient execSubscription(SubscriptionCallback<Post> callback, String boardName)
			throws GraphQLRequestPreparationException, GraphQLRequestExecutionException, IOException {
		
		// Execution of the full request, with one GraphQL Variable: boardNameParam (as defined in the above query)
		// Then you can provide the list of parameters, by pair: the parameter's name then its value, here: "boardNameParam", boardName
		return subscriptionRequest.execSubscription(callback, Post.class, "boardNameParam", boardName);
	}
}

The callback is an instance of [SubscriptionCallback<Post>](https://github.com/graphql-java-generator/graphql-maven-plugin-project/blob/master/graphql-java-runtime/src/main/java/com/graphql_java_generator/client/SubscriptionCallback.java). This callback will receive all the notifications for this subscription, especially:

  • onMessage(T t), will be called for each received message from the subscription. In our sample, T is a Post
  • onClose(int statusCode, String reason) when the subscription is closed
  • onError(Throwable cause) when an error occurs

Partial requests

In each query/mutation/subscription class, the plugin also generates Xxxx and XxxxWithBindValues methods, where Xxxx is successively each query/mutation/subscription defined in this query/mutation/subscription object.

In these methods:

  • The query/mutation/subscription parameters (as defined in the GraphQL schema) become parameters of the relevant generated java methods. So you don't need to define and map bind parameters for them.
    • But you can still use bind parameters for input parameters of the fields you request, of course
  • The subscription methods return an instance of SubscriptionClient.
    • This interface has only one method: unsubscribe(), which allows to unsubscribe from this subscribed subscription. This frees resources on both the client and the server, and the network of course.

Below is a sample of the client code:

@Component
public class SubscriptionRequests {

	@Autowired
	SubscriptionExecutor subscriptionTypeExecutor;
	
	GraphQLRequest subscriptionRequest;
	
	// Let's prepare the request, once the bean is ready (and the autowired attributes have been set by Spring)
	@PostConstruct
	public void init() {
		subscriptionRequest = subscriptionTypeExecutor.getSubscribeToNewPostGraphQLRequest
			("{id date author publiclyAvailable title content}");
	}

	public SubscriptionClient execSubscription(PostSubscriptionCallback callback)
			throws GraphQLRequestPreparationException, GraphQLRequestExecutionException, IOException {
		
		// Execution of a partial request. The subscribeToNewPost has one parameter: boardName. This parameter is
		// expected from the subscribeToNewPost, as this is a partial request.
		return subscriptionTypeExecutor.subscribeToNewPost(subscriptionRequest, callback, "Board name 1");
	}
}

The subscription specific part is the creation of the callback. The code for the PostSubscriptionCallback class used in the above sample is available on github.

Of course, you can use bind variables, as with queries and mutations.

Use direct queries

If you don't want to store the GraphQLRequest, you can avoid that, by using direct queries. The overhead that exists at each execution is not an issue here, as you'll probably execute the subscription only once.

You still need to provide the callback, that'll receive the notifications you've subscribed to.

Here is a sample with the bind parameters value given as method parameters:

@Component
public class SubscriptionRequests {

	@Autowired
	SubscriptionExecutor subscriptionExecutor;

	public SubscriptionClient subscribe(PostSubscriptionCallback<Post> postSubscriptionCallback) {
		// The subscription request accepts one parameter. If you don't want to provide it, you can give it the null value
		return subscriptionExecutor.subscribeToNewPost("{id date author publiclyAvailable title content}", postSubscriptionCallback, "Board name 1");
	}
}
Clone this wiki locally