I want to fetch the response received from microservice in gateway and add that response to a new ConsumerResponse Object and set that as the new response to my UI in Post Filter of Gateway.
Say my response from microservice is a ResponseEntity of Object, Json Object like below,
{
"userDetails": {
"userId": 24,
"userName": "ABC",
"description": "ABC from ZZZ",
"registrationStatus": "REGISTERED",
"registrationTime": [
2022,
5,
23,
21,
17,
41,
465000000
],
"lastUpdatedTime": [
2022,
5,
23,
21,
17,
41,
465000000
]
}
}
Below is my ConsumerResponse Class, in which i want to set the above Json data in T data,
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class ConsumerResponse implements Serializable {
private static final long serialVersionUID = 1L;
private ConsumerResponse() {}
public static <T> ResponseEntity<ResponseEnvelope<Object>> ok(
T data, String apiVersion, Status status, HttpStatus httpStatus) {
return ResponseEntity.status(httpStatus)
.body(ResponseEnvelope.builder().apiVersion(apiVersion).data(data).status(status).build());
}
}
Below is my Gateway Filter class, Took reference from this link How to get Original response body in Spring cloud gateway (Webflux) Post filter
In the above link, its creating a new String response body, but i want the response received from the microservice.
package org.xyz.gateway.filter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.stream.Collectors;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Component
public class AuthFilter implements GlobalFilter {
private final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
@Autowired
private IdService idService;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// code to fetch id from request
MyResult response = idService.getEntitlements(id);
ArrayList<String> rolesList = response.getRoles()
.values()
.stream()
.distinct()
.collect(Collectors.toCollection(ArrayList::new));
ServerHttpRequest httpRequest = exchange.getRequest()
.mutate()
.header("id", id)
.header("roles", rolesList.toString())
.build();
ServerWebExchange mutatedExchange = exchange
.mutate()
.request(httpRequest)
.build();
return chain.filter(mutatedExchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
HttpStatus responseStatus = serverHttpResponse.getStatusCode();
DataBuffer dataBuffer = null;
String path = exchange.getRequest().getPath().toString();
ServerHttpRequest serverHttpRequest = exchange.getRequest();
DataBufferFactory dataBufferFactory = serverHttpResponse.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = getDecoratedResponse(path, serverHttpResponse, serverHttpRequest, dataBufferFactory);
try {
dataBuffer = dataBufferFactory.wrap(
new ObjectMapper().writeValueAsBytes(
// need to set the response data here in ConsumerResponse Object below
ConsumerResponse.ok(decoratedResponse.toString(), GatewayConstants.VERSION, Status.OK, responseStatus)));
} catch (JsonProcessingException e) {
dataBuffer = serverHttpResponse.bufferFactory().wrap("".getBytes());
}
logger.info("decoratedResponse = {}", decoratedResponse);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
serverHttpResponse.getHeaders().setContentLength(decoratedResponse.toString().length());
serverHttpResponse.writeWith(Mono.just(dataBuffer)).subscribe();
exchange.mutate().response(serverHttpResponse).build();
}));
}
private ServerHttpResponseDecorator getDecoratedResponse(String path, ServerHttpResponse response, ServerHttpRequest request, DataBufferFactory dataBufferFactory) {
return new ServerHttpResponseDecorator(response) {
@Override
public Mono<Void> writeWith(final Publisher<? extends DataBuffer> body) {
logger.info("writeWith entering(...)---> with body = {} ", body);
if (body instanceof Flux) {
logger.info("Body is Flux");
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
DefaultDataBuffer joinedBuffers = new DefaultDataBufferFactory().join(dataBuffers);
byte[] content = new byte[joinedBuffers.readableByteCount()];
joinedBuffers.read(content);
String responseBody = new String(content, StandardCharsets.UTF_8);//MODIFY RESPONSE and Return the Modified response
logger.debug("requestId: {}, method: {}, url: {}, \nresponse body :{}", request.getId(), request.getMethodValue(), request.getURI(), responseBody);
return dataBufferFactory.wrap(responseBody.getBytes());
})).onErrorResume(err -> {
logger.error("error while decorating Response: {}",err.getMessage());
return Mono.empty();
});
}
return super.writeWith(body);
}
};
}
}
Any help would be greatly appreciated. Thanks in advance.