The client mode makes it easy for a Java GraphQL client-side application, to execute queries/mutations/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.
The plugin manages two kinds of request:
It manages two ways of executing the request:
Both kinds of requests, and both modes of execution allows to use bind parameters into your queries/mutations/subscriptions (see below for more information on that)
When the plugin generates the query/mutation/subscription java classes (one for each), it generates two families of methods: Full requests, and Partial requests, as introduced on the top of this page.
In either case, you can call query and mutation in the exact same way. You'll only find queries, in the samples below. But mutations work the same.
Full requests are only valid for queries and mutations. Subscriptions work only with Partial Request. See the Client Subscription page.
For each query/mutation/subscription in the GraphQL schema, a Java class is generated.
The exec and execWithBindValues methods allows you to execute full GraphQL queries, that is: the full GraphQL request, as it would work in the graphiql interface. So you can test your request in graphiql, then parse the tested request into you code, as a Full Request (see below for sample).
This is interesting when:
You'll find samples in the sample projects, in the test part of the client samples.
To use full request, you need to (sample follows):
To execute the request, you must use the execQuery/execMutation method of your GraphQLRequest instance, to get the proper response. This response is the query/mutation response type. So, to get the real result from the server, you must call the getter that is link to your request, getBoards() in the above sample.
GraphQLRequest request; void setup() { // If you have one GraphQL endpoint, use the static configuration. // The classname of the Query or Mutation is the type name, as defined in the GraphQL schema GraphQLRequest.setStaticConfiguration(new GraphQLConfiguration(Main.GRAPHQL_ENDPOINT_URL)); // Create the GraphQL request request = new GraphQLRequest("" // + "fragment topic on Topic {title posts(since: &sinceParam, memberId: ?memberIdParam, memberName: \"?\"){id} author{id}}\r" + "query{boards{id name topics {id ...topic}}}"); } void exec(Date since) { // This sample : // - gives a value for the mandatory (as it starts with &) sinceParam bind parameter, // - gives no value for the optional (as it starts with ?) memberIdParam bind parameter. // So only the since bind parameter will be sent to the server. List<Board> boards = request.execQuery("sinceParam", since).getBoards(); // Do something with boards ... }
In the GraphQL query, you can use:
Please note that the bind parameters can be provided as a map, where the key is the parameter name, by using the xxxWithBindValues(GraphQLRequest, [xxx], Map), where [xxx] is the list of values for the query/mutation.
The previous sample then becomes:
GraphQLRequest request; void setup() { // If you have one GraphQL endpoint, use the static configuration. // The classname of the Query or Mutation is the type name, as defined in the GraphQL schema GraphQLRequest.setStaticConfiguration(new GraphQLConfiguration(Main.GRAPHQL_ENDPOINT_URL)); // Create the GraphQL request request = new GraphQLRequest("" // + "fragment topic on Topic {title posts(since: &sinceParam, memberId: ?memberIdParam, memberName: \"?\"){id} author{id}}\r" + "query{boards{id name topics {id ...topic}}}"); } void exec(Date since, String memberName, String memberId) { Map<String, Object> params = new HashMap<>(); params.put("sinceParam", since); params.put("memberName", memberName); params.put("memberId", memberId); // This sample : // - gives a value for the mandatory (as it starts with &) sinceParam bind parameter, // - gives no value for the optional (as it starts with ?) memberIdParam bind parameter. // So only the since bind parameter will be sent to the server. List<Board> boards = request.execQuery(params).getBoards(); // Do something with boards ... }
For each query/mutation/subscription class, the plugin also generates XxxxEXecutor classes, where Xxxx is the query/mutation/subscription GraphQL type name. These classes contain Yyyy and YyyyWithBindValues methods, where Yyyy is successively each query/mutation/subscription defined in this query/mutation/subscription object.
As subscriptions work differently, they are documented in the Client Subscription page.
These methods are easier to use as:
Below is a sample of the client code:
QueryTypeExecutor queryExecutor; GraphQLRequest topicsRequest; void setup() { // Instanciate a Query executor, with the relevant GraphQL endpoint queryExecutor = new QueryTypeExecutor("https://your.server/graphql"); // Create the GraphQL request // This prepares a GraphQ Request that will execute: topics{id date author{name email alias id type} nbPosts} topicsRequest = queryExecutor.getTopicsGraphQLRequest("{id date author{name email alias id type} nbPosts}"); } void exec() { // The topic query accepts one parameter. If you don't want to provide it, you can give it the null value List<Topic> topics = queryExecutor.topics(topicsRequest, "a board name"); // Do something with topics ... }
This method needs less code, in your application.
Directives can be defined for the requested fields, or their parameters. If you need to define directives at the query/mutation/subscription level, you need to execute a Full Request (see here above).
The bind parameters works as specified for the Full queries.
Of course, you can use input parameters for field or directives.
Below is a sample of a request, with bind parameters:
QueryTypeExecutor queryExecutor = new QueryTypeExecutor("https://your.server/graphql"); GraphQLRequest topicsRequest; void setup() { // ?memberId is an optional bind parameter, of name "memberId" // ?memberName is an optional bind parameter, of name "memberName" // ?sinceParam is an optional bind parameter, of name "sinceParam": you must provide it at execution time, or // a GraphQLRequestExecutionException will be thrown. topicsRequest = queryExecutor.getTopicsGraphQLRequest("{id date author{name email alias id type} nbPosts " + "posts(memberId:?memberId, memberName: ?memberName, since: &sinceParam){id date author{name email alias}}}"); } void exec(Date since, String memberName, String memberId) { // The topic query, as defined in the GraphQL schema, has one parameter: the board name. // This parameter is a paremeter of the topics method // You can then as many couples ("bindParameterName", bindParameterValue) that you want, in any order List<Topic> topics = queryExecutor.topics(topicsRequest, "a board name","sinceParam", since, "memberName", memberName, "memberId", memberId); // Do something with topics ... }
Please note that the bind parameters can be provided as a map, where the key is the parameter name, by using the xxxWithBindValues(GraphQLRequest, [xxx], Map), where [xxx] is the list of values for the query/mutation/subscription.
The previous sample then becomes:
QueryTypeExecutor queryExecutor = new QueryTypeExecutor("https://your.server/graphql"); GraphQLRequest topicsRequest; void setup() { topicsRequest = queryExecutor.getTopicsGraphQLRequest("{id date author{name email alias id type} nbPosts " + "posts(memberId:?memberId, memberName: ?memberName, since: &sinceParam){id date author{name email alias}}}"); } void exec(Date since, String memberName, String memberId) { Map<String, Object> params = new HashMap<>(); params.put("sinceParam", since); params.put("memberName", memberName); params.put("memberId", memberId); // The topic query, as defined in the GraphQL schema, has one parameter: the board name // This parameter is a paremeter of the topics method List<Topic> topics = queryExecutor.topicsWithBindValues(topicsRequest, "a board name", params); // Do something with topics ... }
If you don't want to store the GraphQLRequest, you can avoid that, by using direct queries. But please note that there is an overhead, as the query must be analyzed at runtime by the plugin to manage bind parameters, and add the __typename GraphQL introspection attribute where it is missing, to insure proper java deserialization of the response.
So using direct queries generates an overhead at each execution, whereas with prepared queries, the request analysis is done only once.
Direct queries are available only for partial queries. The input parameters for fields and directive are provided the same way as for full queries:
Here is a sample with the bind parameters value given as method parameters:
QueryTypeExecutor queryExecutor = new QueryTypeExecutor("https://your.server/graphql"); void exec(Date since, String memberName, String memberId) { // The topic query accept one parameter. // You can then as many couples ("bindParameterName", bindParameterValue) that you want. List<Topic> topics = queryExecutor.topicsWithBindValues("{id date author{name email alias id type} nbPosts " + "posts(memberId:?memberId, memberName: ?memberName, since: &sinceParam){id date author{name email alias}}}", // One parameter for this query, in the GraphQL schema "a board name", // Then the parameters name and value: "sinceParam", since, "memberName", memberName, "memberId", memberId, ); // Do something with topics ... }
Here is a sample with the bind parameters value given as a map:
QueryTypeExecutor queryExecutor = new QueryTypeExecutor("https://your.server/graphql"); void exec(Date since, String memberName, String memberId) { Map<String, Object> params = new HashMap<>(); params.put("sinceParam", since); params.put("memberName", memberName); params.put("memberId", memberId); // The topic query accept one parameter. // You can then as many couples ("bindParameterName", bindParameterValue) that you want. List<Topic> topics = queryExecutor.topicsWithBindValues("{id date author{name email alias id type} nbPosts " + "posts(memberId:?memberId, memberName: ?memberName, since: &sinceParam){id date author{name email alias}}}", // One parameter for this query, in the GraphQL schema "a board name", // The bind values are in this map params); // Do something with topics ... }