vertx-web
vertx-web copied to clipboard
Body ignored in OpenAPI requests sent to Vert.x using vertx-web-openapi version 4.3
I found a bug that did not exist in 4.2., but was introduced in vertx-web-openapi version 4.3.. If I send a PATCH request to an API defined with openapi for example, the body is ignored and set to null which results in an error.
Version
Which version(s) did you encounter this bug ?
vertx-web-openapi version 4.3
Context
I encountered an exception which looks suspicious while ...
Sending a REST request to an API defined with openapi and RouterBuilder.
Do you have a reproducer?
I have a reproducer in GitHub here: https://github.com/computate/vertx-bug
And a reproducer container image in quay.io: quay.io/computate/vertx-bug:latest
Steps to reproduce
You can run the Vert.x openapi spec with podman or docker like this:
podman run -p 12080:12080 quay.io/computate/vertx-bug:latest
Then you can send a PATCH request in a separate terminal to see the error like this:
curl -X PATCH -H 'Content-Type: application/json' -d '{"do": "stuff"}' http://localhost
:12080/
This results in the following error:
[vert.x-eventloop-thread-0] INFO org.computate.vertx.bug.verticle.MainVerticle - Configure OpenAPI succeeded
[vert.x-eventloop-thread-1] INFO org.computate.vertx.bug.verticle.MainVerticle - Configure OpenAPI succeeded
[vert.x-eventloop-thread-0] INFO org.computate.vertx.bug.verticle.MainVerticle - Configure API completed
[vert.x-eventloop-thread-1] INFO org.computate.vertx.bug.verticle.MainVerticle - Configure API completed
[vert.x-eventloop-thread-0] INFO org.computate.vertx.bug.verticle.MainVerticle - Start server
[vert.x-eventloop-thread-1] INFO org.computate.vertx.bug.verticle.MainVerticle - Start server
[vert.x-eventloop-thread-1] INFO org.computate.vertx.bug.verticle.MainVerticle - Start server succeeded
[vert.x-eventloop-thread-0] INFO org.computate.vertx.bug.verticle.MainVerticle - Start server succeeded
[vert.x-eventloop-thread-4] INFO org.computate.vertx.bug.verticle.MainVerticle - Started main verticle.
[vert.x-eventloop-thread-1] ERROR io.vertx.ext.web.RoutingContext - Unhandled exception in router
io.vertx.ext.web.validation.BodyProcessorException: [Bad Request] Body application/json parsing error: Null body
at io.vertx.ext.web.validation.BodyProcessorException.createParsingError(BodyProcessorException.java:52)
at io.vertx.ext.web.validation.impl.body.JsonBodyProcessorImpl.process(JsonBodyProcessorImpl.java:33)
at io.vertx.ext.web.validation.impl.ValidationHandlerImpl.validateBody(ValidationHandlerImpl.java:247)
at io.vertx.ext.web.validation.impl.ValidationHandlerImpl.handle(ValidationHandlerImpl.java:143)
at io.vertx.ext.web.validation.impl.ValidationHandlerImpl.handle(ValidationHandlerImpl.java:18)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:140)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at io.vertx.ext.web.handler.impl.ResponseContentTypeHandlerImpl.handle(ResponseContentTypeHandlerImpl.java:54)
at io.vertx.ext.web.handler.impl.ResponseContentTypeHandlerImpl.handle(ResponseContentTypeHandlerImpl.java:28)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at io.vertx.ext.web.handler.impl.SessionHandlerImpl.handle(SessionHandlerImpl.java:321)
at io.vertx.ext.web.handler.impl.SessionHandlerImpl.handle(SessionHandlerImpl.java:37)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at io.vertx.ext.web.impl.RouterImpl.handle(RouterImpl.java:68)
at io.vertx.ext.web.impl.RouterImpl.handle(RouterImpl.java:37)
at io.vertx.core.http.impl.Http1xServerRequestHandler.handle(Http1xServerRequestHandler.java:67)
at io.vertx.core.http.impl.Http1xServerRequestHandler.handle(Http1xServerRequestHandler.java:30)
at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:55)
at io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:158)
at io.vertx.core.http.impl.Http1xServerConnection.handleMessage(Http1xServerConnection.java:145)
at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:157)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:153)
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.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
at io.netty.handler.codec.http.websocketx.extensions.WebSocketServerExtensionHandler.channelRead(WebSocketServerExtensionHand
ler.java:99)
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.vertx.core.http.impl.Http1xUpgradeToH2CHandler.channelRead(Http1xUpgradeToH2CHandler.java:120)
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.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:333)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:454)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
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.vertx.core.http.impl.Http1xOrH2CHandler.end(Http1xOrH2CHandler.java:61)
at io.vertx.core.http.impl.Http1xOrH2CHandler.channelRead(Http1xOrH2CHandler.java:38)
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.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.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
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:829)
Caused by: io.vertx.ext.web.validation.MalformedValueException: Null body
at io.vertx.ext.web.validation.impl.body.JsonBodyProcessorImpl.process(JsonBodyProcessorImpl.java:34)
... 62 more
Extra
- Anything that can be relevant such as OS version, JVM version
Hey, I have the same problem with vertx 4.4.4
and POST
requests. If I go back to vertx 4.3.0
the issue does not appear. If i bump the version to 4.3.1
, the problem appears. So the changes in 4.3.1
might have introduces the issue.
Hi @computate and @JonasTaulien,
I encountered the same issue while using Vert.x >= 3.4.1 with POST requests. It seems that the changes introduced in Vert.x 4.3.1 might have altered the behaviour, specifically affecting the configuration of the BodyHandler
. This alteration resulted in the BodyHandler
being added only when global handlers are not configured. In my scenario, where I was adding global handlers, this unintentionally prevented the BodyHandler
from being properly configured.
As stated in the Vert.x documentation, configuring the BodyHandler is essential to gain access to request bodies. To address this situation, if we are using global handlers and still require access to the request body, it becomes critical to configure the BodyHandler as early as possible in the handler hierarchy. This can be achieved by incorporating the following line:
rootHandler(BodyHandler.create())
I hope this information helps shed light on the issue. If you have any further questions or insights, please feel free to share.
Hey @ines-soares thanks for your notes and especially the link to the commit changes! It helped my do understand and fix the issue.
I am using the io.vertx.reactivex.ext,web.openapi.RouterBuilder
and until 4.3.1
I never had to manually add a BodyHandler
. That is also stated in the Vert.x OpenAPI documentation
But I do add some other global handlers via the rootHandler
. The code changes you have provided explain, why I now have the problem that there is no BodyHandler
(globalHandlers.isEmpty()
check instead bodyHandler != null
).
So after adding the BodyHandler
manually with the rootHandler
method I was able to upgrade to 4.4.5
successfully. I do not get the error anymore. 🎉🎉🎉
@vietj I would suggest to update the Vert.x OpenAPI documentation for the BodyHandler
and for the rootHandler
method so it states, that the BodyHandler
has to be manually added, if at least one global handler was added by using the rootHandler
method.
Hi, there is a complete new rebuild of the OpenAPI Router [1], which hopefully solves the problem. As I understood the problem is already solved and only a documentation change is requested. So I think this is also solved, because we removed the documentation for this deprecated version.
I am closing this issue now, as the ticket refers to a version of OpenAPI Router that is no longer supported. If the bug still occurs with the new OpenAPI router version, I would be very happy if you would open a new issue.
[1] https://vertx.io/docs/vertx-web-openapi-router/java/