If you setup functional endpoints as described in the documentation, like so:
val route = router {
"/person".nest {
GET("/{id}", handler::getPerson)
GET("", handler::listPeople)
POST("/person", handler::createPerson)
}
}
... then you try to add a response header of X-My-Response-Header
with a value of foo
to these routes using filter
or after
, like so:
val route = router {
"/person".nest {
GET("/{id}", handler::getPerson)
GET("", handler::listPeople)
POST("/person", handler::createPerson)
after { request, response -> ServerResponse.from(response).header("X-My-Response-Header", "foo").build() }
}
}
... you'll notice your header gets added, but your body is gone. This is because ServerResponse.from()
doesn't copy the body, only the status code and responses. From the docs:
Create a builder with the status code and headers of the given response.
So say you eschew immutability and you try to mutate it:
val route = router {
"/person".nest {
GET("/{id}", handler::getPerson)
GET("", handler::listPeople)
POST("/person", handler::createPerson)
after { request, response -> response.headers().set("X-My-Response-Header", "foo"); response }
}
}
... this will throw an exception. That's because ServerResponse
is (rightly) immutable and uses ReadOnlyHttpHeaders
, and that implementation of HttpHeaders
will (rightly) throw an exception if you attempt to modify it in any way.
The combination of these two limitations means you cannot add a response header in filters because:
1. You can't create a new ServerResponse
with the new header and fetch the body of the previous ServerResponses
intact (outside of some extreme measures).
2. You can't mutate the existing ServerResponse
to have the new header.
Comment From: poutsma
You can copy the raw contents from the original response like so:
after { request, response -> ServerResponse.from(response).header("X-My-Response-Header", "foo").body(response.bodyToFlux(DataBuffer.class)) }
Comment From: carusology
@poutsma There isn't a bodyToFlux()
method on ServerResponse
(Source). That's on ServerRequest
(Source)
Comment From: poutsma
I'm sorry for closing the issue prematurely.
It looks like there is no way to accomplish this with after
, but you can use filter
:
.filter((request, next) ->
next.handle(request). // invoke the next handler in the chain
flatMap(response ->
ServerResponse.status(response.rawStatusCode()) // recreate the response
.headers(headers -> {
headers.addAll(response.headers());
headers.add("X-My-Response-Header", "foo");
})
.build(response::writeTo)))
.build();
Sorry about using Java; my Kotlin is not that great. Hopefully you will be able to convert it.