bug: client throws error when parsing response with error.
Hi, I am experiencing an issue when using DGS for integration tests. I am using MonoGraphQLClient and I have my test queries in a file. Everything works fine until I try to test errors. The tests that are supposed to check if directives to check ranges work. The client throws an error instead of parsing the response.
This is what the tested endpoint returns to the client:
{
"errors": [
{
"message": "The field topicsProjects must be between $1 and $100",
"locations": [
{
"line": 3,
"column": 3
}
],
"path": [
"topicsProjectsQueries",
"topicsProjects"
],
"extensions": {
"classification": {
"type": "ExtendedValidationError",
"validatedPath": [
"topicsProjectsQueries",
"topicsProjects",
"paging",
"size"
],
"constraint": "@Range"
}
}
}
],
"data": null
}
This is the error I get.
com.jayway.jsonpath.spi.mapper.MappingException: java.lang.IllegalArgumentException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: java.util.ArrayList[0]->com.netflix.graphql.dgs.client.GraphQLError["extensions"]->com.netflix.graphql.dgs.client.GraphQLErrorExtensions["classification"])
at com.jayway.jsonpath.spi.mapper.JacksonMappingProvider.map(JacksonMappingProvider.java:58)
at com.jayway.jsonpath.internal.JsonContext.convert(JsonContext.java:121)
at com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:103)
at com.netflix.graphql.dgs.client.GraphQLResponse.<init>(GraphQLResponse.kt:52)
at com.netflix.graphql.dgs.client.WebClientGraphQLClient.handleResponse(WebClientGraphQLClient.kt:146)
at com.netflix.graphql.dgs.client.WebClientGraphQLClient.access$handleResponse(WebClientGraphQLClient.kt:42)
at com.netflix.graphql.dgs.client.WebClientGraphQLClient$reactiveExecuteQuery$3.invoke(WebClientGraphQLClient.kt:136)
at com.netflix.graphql.dgs.client.WebClientGraphQLClient$reactiveExecuteQuery$3.invoke(WebClientGraphQLClient.kt:136)
at com.netflix.graphql.dgs.client.WebClientGraphQLClient.reactiveExecuteQuery$lambda$3(WebClientGraphQLClient.kt:136)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:245)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:305)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:122)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:539)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337)
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2071)
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:413)
at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:431)
at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:485)
at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:712)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800)
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:499)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:397)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:102)
at reactor.core.publisher.Mono.block(Mono.java:1712)
at cz.cvut.fel.czm.temataprojectslogic.BaseCT.graphQlRequestFromFile(BaseCT.kt:67)
The method where the error is thrown.
fun graphQlRequestFromFile(file: String, variables: Map<String, Any> = emptyMap()): GraphQLResponse {
val query = javaClass.getResource(file)?.readText()
?: throw IllegalStateException("Cannot read query")
return graphQlTestClient.reactiveExecuteQuery(query, variables).block() ?: throw IllegalStateException(
"Null response"
)
}
Expected behavior
I would expect the client to parse the response normally.
Actual behavior
The response is not parsed and an error is invoked.
Steps to reproduce
Use the client to request from an endpoint that returns an error(Like the one above.).
Thanks a lot
I believe this issue was fixed in v8.2.5 (see #1802). What version of DGS are you on?
Hey, we are on 7.XX. I will migrate (it will take some time since there are some breaking changes.) to 8.XX and see if the issue persists.
Fixed in 7.X