When does webflux validate the request body? - spring-webflux

#Controller
public class IndexController {
#Resource
WebClient webClient;
#PostMapping
public Mono<User> index(#Valid #RequestBody Mono<User> user){
// I'm using webclient to call another service, just pass the mono object like this
return this.getResponse(user);
}
private Mono<User> getResponse(Mono<User> user) {
return webClient.post()
.body(user,User.class)
.retrieve().bodyToMono(User.class);
}
}
In above scenario, I don't need to operate the request body. request body will not be validated.
How can I make webflux to validate the request body?

In that scenario, SpringMVC(not sure which componment will do) connot vaildate the Mono, so I cannot get a webexchangebindexception. the validation will occur when the Mono is subscribed which is also when webclient actually send the message.
before webclient actually sending message, validation will be done,webexchangebindexception will be catch by webclient. webclient will wrap this exception into webclientrequestexception by default. we can add our own exception handler to webclient so that we can just throw webexchangebindexception to our global exception handler.

Related

Different JSON (de)serialization configs on different endpoints using Spring WebFlux

My micro service needs to communicate with 2 different services over HTTP. 1 has an API contract with snake_case JSON, while the other uses camelCase. How can I configure WebFlux to deserialize and serialize JSON with a certain Jackson ObjectMapper on a set of functional endpoints, while use another one on different endpoints?
The WebFlux documentation shows how to wire in another ObjectMapper, but this applies to all the endpoints of my API. So right now either all my JSON in snake_case or in camelCase. Cant find any resource to solve this issue, but it must be doable right?
Update: to make it clear I want to configure the web server which receives the requests from other services, not the webclient for sending http requests myself. I know how to do the latter.
you can use the #JsonNaming annotation on the classes you want to serialize/deserialize and specify what type of naming strategy you want.
jackson-advanced-annotations
Okay, so this is not the cleaned up solution, I will use this solution from our library, but the basic gist of my work around looks like this:
#Controller
public class Handler {
private ObjectMapper mapper;
public Handler(#Qualifier("snakeCaseWrapper") ObjectMapper mapper) {
this.mapper = mapper;
}
Mono<ServerResponse> returnUser(final ServerRequest request) {
//REQUEST DESERIALIZATION
var messageReader = new DecoderHttpMessageReader<>(new Jackson2JsonDecoder(mapper));
var configuredRequest = ServerRequest.create(request.exchange(), List.of(messageReader));
//RESPONSE SERIALIZATION
return configuredRequest.bodyToMono(UserDto.class)
.map(userDto -> {
try {
return mapper.writeValueAsString(userDto);
} catch (JsonProcessingException e) {
e.printStackTrace();
//properly handle the error here
return "";
}
})
.flatMap(json -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(json))
);
}
}
This is the only way I could find to programatically choose which kind of ObjectMapper I want to use for a specific endpoint/handler method for request deserialization. For response serialization, the trick was to first use the ObjectMapper to serialize the response body to a String, and put that String into the response with BodyInserters.fromObject(json) .
It works, so I'm happy with it.

Is there a helper method to extract origin host from request (to build a link)

I receive request via a router :
#Bean
public RouterFunction<ServerResponse> routerFunction() {
return nest(path(API_PATH), route(GET("/"), indexHandler::getIndex));
}
handle by a method :
public Mono<ServerResponse> getIndex(ServerRequest request) {
...
}
I need to extract the url use to request the service, I have different cases, sometimes request are direct to service, sometimes request go through proxy (and add X-Forwarded-Path,X-Forwarded-Path headers).
Is there a helper method, to extract this details from ServerRequest object ?

Send Custom response from ProvideFault() method in WCF

I am using IErrorHandler to catch the exceptions for handling and logging purpose in my WCF service. I catch exception in ProvideFault(.....) method and from here I send Fault Exception to the client.
Below is the sample code for it..
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException<MyResponse> fe = new FaultException<MyResponse>(
new ErrorResponse
{
MessageCode = "ERR001",
MessageDetail = "Error Occured at server Side"
});
MessageFault faultMsg = fe.CreateMessageFault();
fault = Message.CreateMessage(version, faultMsg, fe.Action);
}
Where MyResponse is the custom type.
Now due to some requirement change, I donot want to send FaultMessage from service. Can I send the MyResponse object from ProvideFault method? Something like as..
MyResponse response = new MyResponse();
response.MessageCode = "ERR001";
response.MessageDetail = "Error Occured at server Side";
Message.CreateMessage(version, response, response.Action);
So this can be handled at the client for all scenarios. The reason for this change is that all the client may not handling FaultException.
I do not want to use try catch in my service and send response from catch, instead I want to use IErrorHandler for this.
Any suggestions would be highly appreciated.

Web API 2.0 - How to validate incoming Request in ASP.NET Web API similar in WCF AfterReceiveRequest(IDispatchMessageInspector member)

I am migrating existing WCF service in to Web API. In WCF have implemented IDispatchMessageInspector Members for validating/Logging incoming request and outgoing reply. Like below
"#region IDispatchMessageInspector Members"
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
//Log the Request with Log4Net
Logging.InfoMessage = string.Format("{0} - {1}", "Before calling ", GetWebMethodName());
Logging.DebugMessage = request.ToString();
Logging.WriteLog();
//Logic to validate Request
}
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//Log the Response with Log4Net
Logging.DebugMessage = reply.ToString();
Logging.InfoMessage = string.Format("{0} - {1}", "After called ", GetWebMethodName());
Logging.WriteLog();
}
#endregion
I would like to achieve the same in webAPI 2.0 . Doing this all the request validation handled Globally as well Logging.
Please share your experience if you have done already..
I would suggest creating a Custom Message Handler. A custom message handler is a class that inherits from the class DelegatingHandler.
All the request coming into a WebAPI request processing cycle are first handled by Request handlers and all the responses going out are lastly processed by handler.
https://www.asp.net/media/4071077/aspnet-web-api-poster.pdf
You could use ActionFilterAttribute.
The OnActionExecuting occurs before the action method is invoked and OnActionExecuted just after. Look here to have an example on how it could be implemented.
Another way could be to create your own Owin middleware. Look here for a simple example that demonstrates how to perform some checks before invoking an action method.

Getting details of the call to a WCF service in custom UserNamePasswordValidator

I have a WCF service setup with my own UserNamePasswordValidator. When authentication fails in the Validate(string userName, string password) method I want to write the details to a log as well as throwing a FaultException.
I want to store details of the particular service method that was being called and the parameters that were passed in as well as the username.
How do I access these details from inside the Validate method?
Example code below:
public class ColesUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (CheckCredentials(userName, password))
{
return;
}
else
{
// do something here to get details of the call to the service and send them to a log file
throw new FaultException("Unknown Username or Incorrect Password");
}
}
It is not possible. Validation runs in different thread and it doesn't have access to WCF contexts. Also no WCF context contains information about service method which was called. Incomming message only contains information about SOAP Action which was requested.
If you want to make some logging implement IErrorHandler. Throw SecurityTokenException from custom validator and handle this expection in ProvideFault of IErrorHandler - create FaultException. In HandleFault of IErrorHandler you can implement logging. For logging you can check if OperationContext.Current is not null (yes it can be if exception is thrown before message processing) and access information about current operation call.