Make a POST call to GraphQL API programmatically using Java
Asked Answered
H

2

11

I have to send a query with some headers and graphQL variables as a POST call to a GraphQL API in java. I also have to send some headers and authentication parameters in the query. Right now, I am doing a manual call in POSTMAN, but I want to do this programmatically. Can you guys help me where to start off. My query and variables are as follows

query sampleQuery($param: SampleQueryParams!, $pagingParam: PagingParams) {
    sampleLookup(params: $param, pagingParams: $pagingParam) {
        ID
        name1
        name2 
    }
}

And my GraphQL variables are as follows :

{"param": {"id": 58763897}, "pagingParam": {"pageNumber": 0, "pageSize": 10 } }

I have no clue where to start at. Could you guys please help

Hargeisa answered 26/11, 2019 at 16:11 Comment(1)
I don't know much about the GraphQL Java Ecosystem but the first step could be to look at a HTTP client library. This should be possible with any HTTP client that can create POST requests.Patois
L
7

Below is a typical graphql endpoint for a java backend

There are 2 basic flows here

1 an endpoint for http request that can handle the graghql query as a string and a map / json representation of the query's input variables

2 the graphql wiring for the backend that collates and returns the data

the backend would typicaly have an endpoint that looks like this (1)

   public Map<String, Object> graphqlGET(@RequestParam("query") String query,
                                      @RequestParam(value = "operationName", required = false) String operationName,
                                      @RequestParam("variables") String variablesJson) throws IOException {...

note we have 3 inputs
a query string,
a string usually json for the querys variables
an optional "operationName"

once we have parsed these input parameters we would typically send them to the graphql implementation for the query

which could look like this (1)

  private Map<String, Object> executeGraphqlQuery(String operationName,
                                                String query, Map<String, Object> variables) {
    ExecutionInput executionInput = ExecutionInput.newExecutionInput()
            .query(query)
            .variables(variables)
            .operationName(operationName)
            .build();

    return graphql.execute(executionInput).toSpecification();
}

here the graphql object has all the wiring to return the data

So a solution is just to post the correctly formatted input parameters to the backend
I often use android and a http client that works with older android versions so a post request in kotlin could look like this as a very simple example

    val client = HttpClients.createDefault()
    val httpPost = HttpPost(url)
    val postParameters = ArrayList<NameValuePair>()
    postParameters.add(BasicNameValuePair("query", "query as string"))
    postParameters.add(BasicNameValuePair("variables", "variables json string"))
    httpPost.entity = UrlEncodedFormEntity(postParameters, Charset.defaultCharset())
    val response = client.execute(httpPost)
    val ret =  EntityUtils.toString(response.getEntity())

please note the implementation for the http post with be dependent on the way the backend java implementation is set up

for the basic http client and post setup many good examples here
How to use parameters with HttpPost

possibly related

graphql allows for a introspection flow which publishes details on the query structure the implementation supports more info here

https://graphql.org/learn/introspection/

[1] https://github.com/graphql-java/graphql-java-examples

Laux answered 26/11, 2019 at 18:18 Comment(1)
This helped. Thanks a lot for the detailed answer!!Hargeisa
K
2

I would recommend using graphql-java-codegen plugin for these purposes.

It provides a possibility to generate classes based on the schema which you can supply to any HTTP client.

For example, GraphQL server has following schema and we want to perform productById query:

type Query {
    productById(id: ID!): Product
}

type Product {
    id: ID!
    title: String!
    price: BigDecimal!
}

graphql-java-codegen will generate all classes required for you to perform a query:

// preparing request
ProductByIdQueryRequest request = new ProductByIdQueryRequest();
request.setId(productId);
// preparing response projection (which fields to expect in the response)
ProductResponseProjection responseProjection = new ProductResponseProjection()
        .id()
        .title()
        .price();

// preparing a composite graphql request
GraphQLRequest graphQLRequest = new GraphQLRequest(request, responseProjection);

// performing a request with the constructed object
ProductByIdQueryResponse responseBody = restTemplate.exchange(URI.create("https://product-service:8080/graphql"),
        HttpMethod.POST,
        new HttpEntity<>(graphQLRequest.toHttpJsonBody()),
        ProductByIdQueryResponse.class).getBody();
// Fetching a serialized object from response
Product product = responseBody.productById();

More examples can be found on GitHub: https://github.com/kobylynskyi/graphql-java-codegen#supported-plugins

Kesley answered 7/9, 2021 at 12:35 Comment(2)
Though the selected answer works, I would prefer this approach because it is more cleaner and structured and all the required classes are automatically generated if you have the schema file. I used this to integrate with one of the payment gateways and it worked very well.Dionnadionne
Does this not mean your coupled to the schema - any underlying change to the servers schema and it’s a direct change in all clients?Salvation

© 2022 - 2024 — McMap. All rights reserved.