added an ExchangeFilterFunction to WebClient which logs request and response but while logging, was unable to log request and response body as a string or JSON. It prints as an object
Tried different castings and retrieving the body as a string using bodyToMono, toEntity but they return an object and not string exactly.
logRequest(clientRequest.url(), clientRequest.method(), clientRequest.headers(), clientRequest.body());
Mono<ClientResponse> response = exchangeFunction.exchange(clientRequest);
ClientResponse clientResponse = response.block();
logResponse(clientResponse.statusCode(), clientResponse.headers(), clientResponse.toString(), clientResponse);
return response;
}```
```private void logRequest(URI uri, HttpMethod method, HttpHeaders httpHeaders, BodyInserter<?, ? super ClientHttpRequest> body) {
log.info("Request: {}",
LogVar.with("Body", body)
);
}
private void logResponse(HttpStatus statusCode, Headers headers, String body, ClientResponse extractor) {
log.info("Response: {}",
, LogVar.with("Body", extractor.bodyToMono(String.class))
);
}```
Expecting Json OR XML whatever the request/response is, to be logged as a string.
Related
I am consuming an API and this one in particular response with nothing but status code 201 in postman. In my code, how do I extract the status code using WebClient?
public HttpStatus createUser(String uuid) throws Exception {
MultiValueMap<String, String> bodyValues = new LinkedMultiValueMap<>();
bodyValues.add("providerCallbackHost", "https://webhook.site/c6c0a388-2af5-41e1-8d6d-c280820affad");
try {
HttpStatus response = webClient.post()
.uri("https://sandbox.momodeveloper.mtn.com/v1_0/apiuser")
.header("X-Reference-Id", uuid)
.header("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY_SECONDARY)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(bodyValues))
.retrieve()
.bodyToMono(HttpStatus.class)
.block();
return response;
} catch (Exception exception) {
throw new Exception(exception.getMessage());
}
}
I read thousand of answers and try to a lot of way but doesn't work.
I really need to change response body when get "401". Because server response is different from other general response when unauthorized.
I'm using retrofit 2. To catch response i'm using Interceptor:
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("authorization", getAccessToken(context));
Request request = requestBuilder.build();
Response response= chain.proceed(request);
if (response.code()==401) {
MediaType contentType = response.body().contentType();
ResponseBody body = ResponseBody.create(contentType, CommonFunctions.getUnAuthorizedJson(context).toString());
return response.newBuilder().body(body).build();
}else{
return response;
}
But still body doesn't change on client.enque method.
You can change body in this way, but Retrofit will eventually see 401 and throw HttpException with standart message, what can be misleading
check that you get your body right:
val errorConverter: Converter<ResponseBody, ErrorResponse> =
retrofit.responseBodyConverter(
ErrorResponse::class.java,
emptyArray()
)
val errorResponse = httpException
.response()
?.errorBody()
?.let (errorConverter::convert)
I try to get list of entity with using rest template, but I get 415 error in line:
ResponseEntity<List<ResponseOrderDto>> responseEntity = rest.exchange
My implementation:
RestTemplate rest = new RestTemplate();
rest.getInterceptors().add((request, body, execution) -> {
ClientHttpResponse response = execution.execute(request,body);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.getHeaders().add("Bearer", contentToken);
return response;
});
ResponseEntity<List<ResponseOrderDto>> responseEntity = rest.exchange(
ORDER_SERVICE_URL + "/by-user",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<ResponseOrderDto>>() {
});
How fix this error?
415 means unsupported content type, so the Content-type header is not correctly set.
Based on your code, I think that the request needs JSON Content-Type header, but you set the content-type header on the response instead of the request.
Change your interceptor to be something like this:
rest.getInterceptors().add((request, body, execution) -> {
request.getHeaders().setContentType(MediaType.APPLICATION_JSON);
request.getHeaders().add("Bearer", contentToken);
ClientHttpResponse response = execution.execute(request, body);
return response;
});
To set the headers at the right time to the request
In my code I am very often using HttpEntity alongside ResponseEntity in a following way:
HttpEntity<?> request = new HttpEntity<String>(myObject, headers);
ResponseEntity<String> response = restTemplate.exchange("someurl", HttpMethod.POST, request, String.class);
and then
response.getBody()
I repeat this code all the time, I was wondering if it is possible to create a generic method that would allow me to get response.body() when I supply it with object I want to send, an url, and a HttpMethod type.
The response body most of the time will be a string, but can be an object.
You can use below code, here the response body and request body are made generic:
public <T, R> T yourMethodName(R requestBody,
MultiValueMap<String, String> headers,
String url,
HttpMethod type,
Class<T> clazz) {
HttpEntity<?> request = new HttpEntity<String>(requestBody, headers);
//You have to create restemplate Obj somewhere
ResponseEntity<T> response = restTemplate.exchange(url, type, request, clazz);
return response.getBody();
}
I have a simple handler in my controller which returns a message
#RequestMapping(value = "/message")
#ResponseBody
public Message get() {
return new Message(penguinCounter.incrementAndGet() + " penguin!");
}
At the same time I can use something like this
#RequestMapping(value = "/message")
ResponseEntity<Message> get() {
Message message = new Message(penguinCounter.incrementAndGet() + " penguin!");
return new ResponseEntity<Message>(message, HttpStatus.OK);
}
What is the difference betweet this two approaches? Let's not take into account HttpStatus :)
ResponseEntity will give you some added flexibility in defining arbitrary HTTP response headers. See the 4th constructor here:
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/http/ResponseEntity.html
ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus statusCode)
A List of possible HTTP response headers is available here:
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Responses
Some commonly-used ones are Status, Content-Type and Cache-Control.
If you don't need that, using #ResponseBody will be a tiny bit more concise.
HttpEntity represents an HTTP request or response consists of headers and body.
// Only talks about body & headers, but doesn't talk about status code
public HttpEntity(T body, MultiValueMap<String,String> headers)
ResponseEntity extends HttpEntity but also adds a Http status code.
// i.e ResponseEntity = HttpEntity + StatusCode
public ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus statusCode)
Hence used to fully configure the HTTP response.
For Ex:
#ControllerAdvice
public class JavaWebExeptionHandler {
#Autowired
ExceptionErrorCodeMap exceptionErrorCodeMap;
#ExceptionHandler(RuntimeException.class)
public final ResponseEntity<ExceptionResponseBody> handleAllExceptions(Exception ex) {
Integer expCode = exceptionErrorCodeMap.getExpCode(ex.getClass());
// We have not added headers to response here, If you want you can add by using respective constructor
return new ResponseEntity<ExceptionResponseBody>(new ExceptionResponseBody(expCode, ex.getMessage()),
HttpStatus.valueOf(expCode));
}
}
#ResponseBody indicates that return value of method on which it is used is bound to the response body
(Mean the return value of method is treated as Http response body)
ResponseEntity<> is a generic class with a type parameter, you can specify what type of object to be serialized into the response body.
#ResponseBody is an annotation, indicates that the return value of a method will be serialized into the body of the HTTP response.
you can set headers using ResponseEntity<>
#ResponseEntity represents a response which includes headers, body and status code.
#ResponseBody only returns the body of the response.