I am trying to implement a request/response client. Here is the basic implementation for it.
Class Request
{
prepareRequest1();
prepareRequest2();
}
Class Response
{
processResponse1();
processResponse2();
}
Class Client
{
connect();
sendRequest();
}
myrequest = new Request();
client = new Client (myserver);
my $rawResponse1 = client.sendRequest (myrequest.prepareRequest1());
myresponse = new Response();
myresponse.processResponse1 ($rawResponse1);
I have three classes namely - Request, Response and Client. Request class contains a function specific to a request. These request are the XML requests. There XML request does not have anything in common except few initial tags (e.g. sessionid etc). All other XML parameters are specific to the type of request. So, Currently I am handing it by creating a separate function for each request. I understand that it has a scalability issue, but please suggest me some other best approach I can apply here.
Similar to the request, the response to each request require a specific treatment. so I have a separate function specific to each type of response I am expecting. Generally you can assume that there is a 1:1 mapping between request and response.
Last is the Client class which hands for connection.
I have almost 50+ such request and response, and I am planning to implement with this approach. As I am in initial stage of development, please suggest me some improvement/best practices to implement such request/response.
Its best if you keep the mapping of the request and response outside of your code. Easier to manage. Keep an xml config file that stores the class names of your request and response tied to a particular type of xml message. You can then obtain the class names and go to that class to process your request and response. Its best to have separate classes to handles these messages rather than separate methods. Thats more scalable. Ensure you have interface for all your request classes and the same for your response classes. This will make it easy to swap your request responses classes easily by modifying the xml config file..
Hope you got it :)
Related
I know sending a body with a GET request isn't the best idea but I'm trying to consume an existing API which requires it.
Sending a body with POST is straight-forward:
webClient.post()
.uri("/employees")
.body(Mono.just(empl), Employee.class)
.retrieve()
.bodyToMono(Employee.class);
It won't work with webClient.get() though, because while the post() method returns a WebClient.RequestBodyUriSpec, the get() method returns WebClient.RequestHeadersUriSpec<?>, which doesn't seem to allow any body definitions.
I've found a workaround for Spring RestTemplate here: RestTemplate get with body,
but had no luck finding any for the new WebClient.
While the other responses are correct that you shouldn't use a body with a GET request, that is not helpful when you do not own, or cannot change the already existing method you are calling.
The problems is WebClient#get returns a WebClient.RequestHeadersUriSpec which does not provide a way for us to set the body.
WebClient#post returns a WebClient.RequestBodyUriSpec which does provide us a way to set the body but will cause us to use the wrong HTTP method, POST instead of GET.
Thankfully for us stuck in this situation there is WebClient#method which returns a WebClient.RequestBodyUriSpec and allows us to set the HTTP method.
webClient.method(HttpMethod.GET)
.uri("/employees")
.body(Mono.just(empl), Employee.class)
.retrieve()
.bodyToMono(Employee.class);
You may still run into issues in your testing libraries though...
A GET reques has no body. It is forbidden (well, not forbidden, but not used at all) by the HTTP specification. You have two approaches here:
Do a POST. It is there just for that.
Use a query string and pass the data in that part of the URL.
Of course, you can attach the needed fields and pass a payload to the GET request, but it will probably be ignored, or worse, identified as an error and rejected by the server, before your served code has access to it. But if you are passing data to the server to do some processing with it, then POST is what you need to use.
Extracted from RFC-7231. HTTP 1.1. Semantics and code:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
(markup is mine)
Reasons for this are, mainly, that a GET method must be idempotent, producing the same output for the same URL, if repeated. POST doesn't have these requirements, so POST is your friend.
I am trying to intercept all incoming HTTP requests and process the body attached to these requests in my Spring MVC (not Spring Boot) app. To implement this "inbound-interceptor", I am using Spring's HandlerInterceptor interface. Once the request is intercepted, I am trying to retrieve the body as follows:
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
Map<String, String[]> params = requestWrapper.getParameterMap();
byte[] body = requestWrapper.getContentAsByteArray();
Referring to this article, the limitations of trying to extract the body this way are:
Content-type of the request must be x-www-form-urlencoded
Method-type must be POST
For the application I am building, I cannot enforce either of these constraints as the calls come from heterogeneous sources beyond my control. Is there some way to override this behavior to allow extraction of the body for requests not supported by default? Or, alternatively, is there another approach to performing this task?
P.S. I am performing logging + some custom processing on the body. So solutions such as the ones mentioned in this answer are not too helpful
Have you tried Logbook? https://github.com/zalando/logbook Works with pure Spring.
Their Default Log Writer looks promising: https://github.com/zalando/logbook/blob/main/logbook-core/src/main/java/org/zalando/logbook/DefaultHttpLogWriter.java
And you may just want to extend this class to log to all Loggers you want.
You can even do something completely different with the request besides logging.
I am working on an internal tool that simulates SOAP responses for different web services that our product uses. This is intended for use in local development.
The idea is to store the SOAP responses in the database as a blob data. During the mapping of a URL keys to a response, the URL keys and expected SOAP response will be stored to the database. The simulated SOAP response will be as a string body in POST request.
The SOAP response will be stored as a blob in the database along with URL keys. If the URL is /configureresponse/{responsetype}/{responsecode}/, then the values of response type and response code will be saved to the database along with the SOAP response as string.
I am building a Spring MVC application for the same. The code snippet is given below
#Controller
#RequestMapping(value = "/configureresponse/{responsetype}/{responsecode}",
method = RequestMethod.POST)
public ModelAndView configureResponse(
#PathVariable String responseType, #PathVariable String responseCode,
#RequestBody String soapResponse) {
}
How do I return a Servlet Response such as 200 OK or 403 Forbidden based on certain conditions?
Is there a way to secure the incoming XML response and the outgoing XML response? This is an internal tool, but I am not sure how to handle XML injection or any other security issues.
UPDATE: How do I secure the application against a billion laughs attack or make it more secure?
Should I be checking for XSRF vulnerability? If yes, how do I do that?
How do I handle simultaneous concurrent inputs for the same response and request?
UPDATE: How do I check if say one thread is updating the response for a given response type and response code, while the other thread is viewing the response for a given response type and response code?
How do I return a Servlet Response such as 200 OK or 403 Forbidden based on certain conditions?
There are several ways to do this. For instance, you could change your return type to a ResponseEntity<String>, which has a constructor that accepts an HttpStatus. Or, you could simply pass in an HttpServletResponse and set the response code there. Knowing Spring, there are probably 20 more valid ways to do this. I would suggest reading through the excellent Reference Guide available on their site.
Is there a way to secure the incoming XML response and the outgoing XML response? This is an internal tool, but I am not sure how to handle XML injection or any other security issues.
Not sure what you mean by "secure". If you mean transmission, then use SSL. If you mean authorization/authentication use Spring Security. If you mean something else, then I am not sure what to offer except to say I need a better explanation of what you want/need.
Should I be checking for XSRF vulnerability? If yes, how do I do that? Any link or tutorial would be welcome.
Security should be a concern, whether it's an internal app or external. Most hacks now-a-days are done by social engineering their way into the intra-net of a company. Take the recent Target breach. I believe they used the AC repair service to gain access to the building. I went to a Schmoocon talk once where a guy hired to test a companies' security actually got a job as a janitor and would plug in a Linux device he built, go mop some floors, then pick up the device which had scanned all their internal networks. So, yes, if you believe you should guard against an attack, then I would say do so.
How do I handle simultaneous concurrent inputs for the same response and request?
Not sure what you mean by this. Spring MVC typically uses session to isolate requests. If two different users request the same thing, they are two different requests for the same thing. I would suggest using some caching so that you are not hitting your DB every time, but other than that I see no problem.
I am creating a simple RESTful web service with simple types successfully. Now I want to pass an object as argument for web service and get the object as response. My scenario is, Parse the XML message as object by using Jaxb and send the object as request for web service. After that in server side it process the requested object and generates the response xml file and send back it as object.
In URL path i give
"http://localhost:8080/SampleWS/rest/checkXML/username=visolve&password=visolve"
for simple type. But in object I don't know how to give the object reference in URL. Please help me how to solve my problem..
Regards
Bathakarai
Just define a very good-looking domain object. JAXB and JAX-RS will do the rest.
JAXB.
#XmlRootElement
class Regards {
#XmlElement
private long sincerely;
}
JAX-RS.
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#POST
#Path("/sincerely")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response sincerely(final Regards regards) {
regards.setSincerely(System.currentTimeMillis());
return Response.ok(regards).build();
}
Though you could certainly include the entire XML content in your URL, I would probably shy away from it.
Think of it this way: if you encode the XML in the URL you're potentially adding more work on both ends. Now the server and client will both need to know how to build the URL properly, and check to make sure everything lines up correctly. What if, in the future, you need to offer a JSON or YAML view of the same content? Now your URL might need to include the content-type as well. What about character-encoding?
All this to say, HTTP provides a terrific transport mechanism which already addresses these concerns. Include the XML as the entity body of the HTTP message, and use the HTTP header to identify what content-type you're sending, character-encoding, etc. This will work both ways (the server and client both can send the XML back/forth), and makes better use of HTTP.
Here's a related link which might help with some of the details. And another.
On a side note, please, please, please tell me you don't plan on sending user-credentials in plain text across an unencrypted link.
I have a use case that required all calls to NewWebService are routed to OldWebService, if the SOAP request does not validate against NewWebService's XSD and WSDL. NewWebService is located on ServerA and OldWebService is on ServerB.
Abstractly, I know I need some mechanism that will allow me to take a SOAP request that hits NewWebService, send it to OldWebService, then return the SOAP result back to the client. My limited experience with spring-ws is making it difficult to decide how to accomplish that.
My first thought was to build a SOAP client into the NewWebService that calls the OldWebService whenever the payload cannot be validated. Is this the best solution, or is there a better way to allow the NewWebService to act as a pass-through for certain requests?
My solution was to write a custom SoapRequestFilter that implements a javax.servlet.Filter and a new class that extends HttpServletRequestWrapper. Since HttpServletRequestWrapper implements the HttpServletRequest interface, extending the wrapper allows you to copy the HttpRequest and act on the stream without consuming the object and causing issues downstream.
Once I had the filter and wrapper, I was able to parse the endpoint and payload from the HttpRequest. If the request needed to be redirected, I created a new HttpUrlConnection to the old SOAP WebService and set the InputStream from that response to the OutputStream of the HttpResponse.
I think Apache Camel can help you in an efficient way.
You can take a look at its proxy example, it's simple and easy to fulfill your requirement.
http://camel.apache.org/cxf-proxy-example.html