Simplest way to make HTTP request in Spring - web-services

In my Spring web application I need to make an HTTP request to a non-RESTful API, and parse the response body back as a String (it's a single-dimension CSV list).
I've used RestTemplate before, but this isn't RESTful and doesn't map nicely on to classes. Whenever I implement something like this 'by hand' (eg using HttpClient) I invariably find out later that Spring has a utility class that makes things much simpler.
Is there anything in Spring that will do this job 'out of the box'?

If you look at the source of RestTemplate you will find that internally it uses
java.net.URL
and
url.openConnection()
that is the standard way in Java to make HTTP calls, so you are safe to use that. If there would be a "HTTP client" utility in spring then the RestTemplate would use that too.

I use the Spring Boot with Spring 4.3 Core inside and found a very simple way to make Http request and read responses by using OkHttpClient. Here is the code
Request request = new Request.Builder().method("PUT", "some your request body")
.url(YOUR_URL)
.build();
OkHttpClient httpClient = new OkHttpClient();
try
{
Response response = httpClient.newBuilder()
.readTimeout(1, TimeUnit.SECONDS)
.build()
.newCall(request)
.execute();
if(response.isSuccessful())
{
// notification about succesful request
}
else
{
// notification about failure request
}
}
catch (IOException e1)
{
// notification about other problems
}

Related

AWS Lambda function - accessing Path and request parameter value

For my POC, created simple lambda function , which will give emp information through rest api.
Created lambda function and access all the emp data using API gateway.
Facing some challenges while accessing particular data.
i am looking for
emp/1 - to retrieve emp id
emp/_search?name="apple" - search name contains apple.
Question is how to retrieve path and request parameters in java code.
public class TestAwsLambdaFunction implements RequestHandler<Map<String, Object>, String> {
#Override
public String handleRequest(Map<String, Object> input, Context context) {
String empID= null;
try {
#SuppressWarnings("unchecked")
Map<String, String> pathParameters = (Map<String, String>) input.get("querystring");
empID= pathParameters.get("id");
System.out.println(empID);
// TO-Do Business logic -
} catch (Exception e) {
// TODO: handle exception
}
return "Hello from Lambda!" + empID;
}
}
What is the best way to expose my data in Rest api call. Bit confused with Lambda or serverless .
have any option to show the data via page wise. Since i am new to AWS. Please guide me
Question is how to retrieve path and request parameters in java code.
You can use mapping template to send $input.params('name') property in the request body to your Lambda function.
What is the best way to expose my data in Rest api call
Use the proxy integration with these guidelines:
Avoid greedy path variables, except perhaps for a catch-all 404.
Avoid using the ANY method.
Define request models and enable request validation (remember it’s off by default).
In your Lambda, check that the content-type header matches one of your request models, and return a 415 Unsupported Media Type status code if it doesn’t (the proxy integration uses the WHEN_NO_MATCH passthrough behavior). After this check, your Lambda can assume the request validation is fully enforced.
By Ben Kehoe
https://read.acloud.guru/how-you-should-and-should-not-use-the-api-gateway-proxy-integration-f9e35479b993
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html#api-gateway-proxy-integration-lambda-function-java
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-call-api.html
https://github.com/vaquarkhan/Serverless-AWS-Lambda-guide/blob/master/01-aws-lambda-serverless-framework/02-building-rest-api-in-nodejs-with-lambda-gateway.md
https://www.puresec.io/blog/aws-security-best-practices-for-api-gateway
https://www.stackery.io/blog/serverless-function-architecture-principles/
https://technology.finra.org/code/enjoying-auto-scaling-integrated-authentication-low-host-cost.html
You need to choose Lambda Proxy Integrations when you set up your API Gateway. Here's official document Set up Lambda Proxy Integrations in API Gateway.
In this case, API Gateway will pass the whole request data to Lambda, including the request headers, query string parameters, URL path variables and so on. Then you can parse the data using your Java code.

getting http session cookies in spring-ws soap web service client

I have a SOAP web service client written with Spring-WS. In response to a logon request, the web service I connect to returns a session cookie in the HTTP response header with a token in it. Each subsequent call to the service requires that cookie with the token. How can I get the session cookie from the response and then add it to the HTTP header on subsequent calls to the service?
To summarize what I'm asking, how do you extract and inject cookies with Spring-WS.
Here is a snippet of code similar to what I am using to call into the web service:
MySessionLogon api = new MySessionLogon();
api.setUsername(username);
api.setPassword(password);
MySessionLogonResponse response = (MySessionLogonResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"http://myserver/soapservice.asmx",
api,
new SoapActionCallback("http://www.myserver.com/MySession_Logon"));
return response;
I have searched the internet and read a lot of things that seem close to what I need, but I haven't seen a good way to get the value of the cookies I need to use. Any help would be appreciated, thanks in advance.
Did you check WebServiceMessageExtractor ?
You could do the following
MySessionLogonResponse response = (MySessionLogonResponse) getWebServiceTemplate()
.sendAndReceive(
"http://myserver/soapservice.asmx",
api,
new SoapActionCallback("http://www.myserver.com/MySession_Logon"),
new WebServiceMessageExtractor<ResponseAndHeader>() {
public ResponseAndHeader extractData(WebServiceMessage message) throws IOException {
TransportContext context = TransportContextHolder.getTransportContext();
HttpComponentsConnection con = (HttpComponentsConnection) context.getConnection();
httpResponse httpResponse = con.getHttpResponse();
//use the method getHeaders from to retrieve the data you want
});

How can I use Play Framework's FakeApplication to stub out calls to web services via play's WS object?

I'm writing some functional tests in play, however I want to test my stack isolated from other http endpoints.
Is there a mechanism for me to say "Direct WS calls to this set of canned responses" or some other way of stubbing out calls to http endpoints that won't be available for automated tests?
Alternatively, how does fakeApplication config get presented to the rest of the application so I can just set the URL to some localhost server which I'll build myself to provide canned responses
You could create a structural type that mimics the WS signature and use that in your code.
type WSLike = {
def url(url: String): WSRequestHolder
}
Then you can inject your own version of a WSLike class. In combination with a mock library I guess you could do about anything you want.
As for the second question. You could call it like this:
val url = Play.current.configuration
.getString("my.webservice.url")
.getOrElse(throw new PlayException(
"Configuration error",
"Could not find my.webservice.url in settings"))
WS.url(url)
Then in your application.conf add the correct url. You can supply a different one using the FakeApplication.
FakeApplication(additionalConfiguration =
Map("my.webservice.url" -> "http://localhost/service"))

Setting MTOM-enabled property dynamically in Apache CXF

I'm developing SOAP web service using Apache CXF framework. My web-method returns either binary data or plain XML depending on request parameters. Most of requests return binary data, so I configured CXF to use MTOM in service responses.
But this is not always useful: when XML is returned, caller side expects to get plain text/xml document rather than multipart one. So I'd like my web service to dynamically change its binding.
CXF documentation has following example:
Endpoint ep = ...; // example does not explain how to get it
SOAPBinding binding = (SOAPBinding)ep.getBinding();
binding.setMTOMEnabled(true); // or false
Question: how can I get Endpoint instance?
I'm using Spring annotation #Endpoint for web-service and #PayloadRoot for web-method.
You can use the following code if you are using on server,
you need to add import javax.xml.ws.Endpoint;
HelloWorldImpl implementor = new HelloWorldImpl();
String address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
From client side
TestMtomService tms = new TestMtomService(wsdlURL, SERVICE_NAME);
TestMtomPortType port = (TestMtomPortType)tms.getPort(PORT_NAME,TestMtomPortType.class);
Binding binding = ((BindingProvider)port).getBinding();
((SOAPBinding)binding).setMTOMEnabled(true);
Refer
If you are downloaded the cxf bundle, code samples for MTOM Server/Client available on following path
apache-cxf-2.7.2\samples\mtom
I created my own marshalled class extended from org.springframework.oxm.jaxb.Jaxb2Marshaller. Only single method is overriden:
public class Marshaller extends Jaxb2Marshaller {
#Override
public void marshal(Object graph, Result result, MimeContainer mimeContainer) throws XmlMappingException {
if ( disableMtom() ) {
super.marshal(graph, result, null);
} else {
super.marshal(graph, result, mimeContainer);
}
}
private boolean disableMtom() {
return ... // depends on response context
}
}
The disableMtom detects if MTOM is disabled from response context. Web service endpoint takes care to pass this context to marshaller somehow.
By default MTOM is enabled.

Webservice having "No such operation: HTTP GET PATH_INFO"

I currently have a SOAP web service and I am trying to access it's endpoint but I keep getting this error:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>
No such operation: (HTTP GET PATH_INFO: /camel-example-reportincident/webservices/incident)
</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
UNIT TEST
package org.apache.camel.example.reportincident;
import junit.framework.TestCase;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.jvnet.mock_javamail.Mailbox;
/**
* Unit test of our routes
*/
public class ReportIncidentRoutesTest extends TestCase {
private CamelContext camel;
// should be the same address as we have in our route
private static String ADDRESS = "cxf://http://localhost:8080/camel-example-reportincident/webservices/incident"
+ "?serviceClass=org.apache.camel.example.reportincident.ReportIncidentEndpoint"
+ "&wsdlURL=report_incident.wsdl";
protected void startCamel() throws Exception {
camel = new DefaultCamelContext();
camel.addRoutes(new ReportIncidentRoutes());
camel.start();
}
protected static ReportIncidentEndpoint createCXFClient() {
// we use CXF to create a client for us as its easier than JAXWS and works
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ReportIncidentEndpoint.class);
factory.setAddress(ADDRESS);
return (ReportIncidentEndpoint) factory.create();
}
public void testRendportIncident() throws Exception {
// start camel
startCamel();
// assert mailbox is empty before starting
Mailbox inbox = Mailbox.get("incident#mycompany.com");
assertEquals("Should not have mails", 0, inbox.size());
// create input parameter
InputReportIncident input = new InputReportIncident();
input.setIncidentId("123");
input.setIncidentDate("2008-08-18");
input.setGivenName("Claus");
input.setFamilyName("Ibsen");
input.setSummary("Bla");
input.setDetails("Bla bla");
input.setEmail("davsclaus#apache.org");
input.setPhone("0045 2962 7576");
// create the webservice client and send the request
ReportIncidentEndpoint client = createCXFClient();
OutputReportIncident out = client.reportIncident(input);
// assert we got a OK back
assertEquals("0", out.getCode());
// let some time pass to allow Camel to pickup the file and send it as an email
Thread.sleep(3000);
// assert mail box
assertEquals("Should have got 1 mail", 1, inbox.size());
// stop camel
camel.stop();
}
}
I am attempting to use CFX endpoint along with my camel routing and when I am putting the endpoint address in the route and then unit testing it I am getting a "No endpoint could be found for: //path/to/endpoint".
I am assuming that the fact that I am getting an error when I try to access the endpoint url is the issue but I do not even know where to begin on figuring out how to fix it.
When I hit my webservice on SOAP UI it runs fine as well. Any help would be greatly appreciated, and I can provide any info that is needed.
Typically, SOAP services are exposed over HTTP using the POST operation. You seem to be trying to access the service using the GET operation.
I am not sure how you try to invoke the service in your unit test, but you need to make sure it's a HTTP/POST call. If you are using plain HTTP, then you could set a header before invoking the HTTP component.
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
Show your unit test for more detailed input.
#grep
I see this post as bit old, but still will try to answer if anyone else with similar problem is able to. Well, I had the same isssue and wondered what were the reason s behind those. here are the two steps that i tried and fixed up the issue. make sure you are able to access the wsdl in browser.
Close the SOAPUI, delete the soapui_workspace.xml created in user folder under C:/users.
Restart the Soap_ui and open up preferences>Proxy setting.
Change from automatic to None.
Create new project.
This did solved my issue and got the response from webservice in SOAPUI.