1

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.

VinodKhade
  • 147
  • 1
  • 2
  • 10

0 Answers0