spring-bootnetflix-dgs

Spring Boot Netflix DGS Client returns 403 while java RestClient returns response


I want to consume a GraphQL api inside my Spring Boot app I have setup code generation and can send queries

But somehow, when sending a query via DgsGraphQlClient i get a 403, while sending with java HttpClient i get the right response

@EventListener(ApplicationReadyEvent.class)
public void test() throws Exception {
    HttpClient client = HttpClient.newBuilder().build();
    // {"query": "{\n  items {\n    id\n    name\n    shortName\n  }\n}"}
    String query = "{\"query\": \"{\\n  items {\\n    id\\n    name\\n    shortName\\n  }\\n}\"}";
    java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()
            .uri(URI.create("https://api.tarkov.dev/graphql"))
            .header("Content-Type", "application/json")
            .header("Accept", "application/json")
            .POST(java.net.http.HttpRequest.BodyPublishers.ofString(query))
            .build();
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    String jsonString = response.body();
    System.out.println(jsonString);
    
    RestClient restClient = RestClient.builder().baseUrl("https://api.tarkov.dev/graphql")
            .defaultHeader("Accept", "application/json")
            .defaultHeader("Content-Type", "application/json")
            .build();
    HttpSyncGraphQlClient graphQlClient = HttpSyncGraphQlClient.create(restClient);
    DgsGraphQlClient dgsGraphQlClient = DgsGraphQlClient.create(graphQlClient);
    // {"query": "{\n  items {\n    id\n    name\n    shortName\n  }\n}"}
    List<Item> traders = dgsGraphQlClient
            .request(new ItemsGraphQLQuery())
            .projection(new ItemsProjectionRoot<>().id().name().shortName())
            .retrieveSync("items")
            .toEntityList(Item.class);
}

The exception i get

org.springframework.web.client.HttpClientErrorException: 403 Forbidden
    at org.springframework.graphql.client.HttpSyncGraphQlTransport.lambda$execute$0(HttpSyncGraphQlTransport.java:78) ~[spring-graphql-1.4.0.jar:1.4.0]
    at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:579) ~[spring-web-6.2.7.jar:6.2.7]
    at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchange(DefaultRestClient.java:533) ~[spring-web-6.2.7.jar:6.2.7]
    at org.springframework.web.client.RestClient$RequestHeadersSpec.exchange(RestClient.java:680) ~[spring-web-6.2.7.jar:6.2.7]
    at org.springframework.graphql.client.HttpSyncGraphQlTransport.execute(HttpSyncGraphQlTransport.java:71) ~[spring-graphql-1.4.0.jar:1.4.0]
    at org.springframework.graphql.client.AbstractGraphQlClientSyncBuilder.lambda$createExecuteChain$2(AbstractGraphQlClientSyncBuilder.java:175) ~[spring-graphql-1.4.0.jar:1.4.0]
    at org.springframework.graphql.client.DefaultGraphQlClient$DefaultRequestSpec.executeSync(DefaultGraphQlClient.java:206) ~[spring-graphql-1.4.0.jar:1.4.0]
    at org.springframework.graphql.client.DefaultGraphQlClient$DefaultRequestSpec.retrieveSync(DefaultGraphQlClient.java:187) ~[spring-graphql-1.4.0.jar:1.4.0]
    at org.springframework.graphql.client.DgsGraphQlClient$RequestSpec.retrieveSync(DgsGraphQlClient.java:183) ~[spring-graphql-1.4.0.jar:1.4.0]
    at ch.gatzka.graphql.Test.test(Test.java:58) ~[main/:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:382) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:254) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:173) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:454) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:387) ~[spring-context-6.2.7.jar:6.2.7]
    at org.springframework.boot.context.event.EventPublishingRunListener.ready(EventPublishingRunListener.java:109) ~[spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.boot.SpringApplicationRunListeners.lambda$ready$6(SpringApplicationRunListeners.java:80) ~[spring-boot-3.5.0.jar:3.5.0]
    at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.boot.SpringApplicationRunListeners.ready(SpringApplicationRunListeners.java:80) ~[spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:332) ~[spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1362) ~[spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1351) ~[spring-boot-3.5.0.jar:3.5.0]
    at ch.gatzka.graphql.GraphqlApplication.main(GraphqlApplication.java:10) ~[main/:na]

Edit: Using request-catcher i found a difference

Java RestClient

POST /test HTTP/1.1
Host: another.requestcatcher.com
Accept: application/json
Content-Length: 66
Content-Type: application/json
User-Agent: Java-http-client/21.0.7

{"query": "{\n  items {\n    id\n    name\n    shortName\n  }\n}"}

Netflix DGS

POST /test HTTP/1.1
Host: another.requestcatcher.com
Transfer-Encoding: chunked
Accept: application/json, application/graphql-response+json
Content-Type: application/json
User-Agent: Java-http-client/21.0.7

41
{"query":"{\n  items {\n    id\n    name\n    shortName\n  }\n}"}
0

Somehow i get a "41" and a "0" inside my body


Solution

  • I found a solution i dont know why it works now, but it works i guess Adding this to my RestClient

    .requestInterceptor(new ClientHttpRequestInterceptor() {
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            log.info(request.toString());
            return execution.execute(request, body);
        }
    })
    

    Somehow works also it removed the Transfer-Encoding header