How to mimic curl REST call with Spring's RestTemplate? - spring

Have an external Restful Web Service which takes in JSON payloads if its is more than one input but if its a single input it just needs the value.
For example, for multiple inputs, this works:
curl -H "Content-Type: application/json" -X POST -d '{ "amount": 10000, "interestRate": ".28", "term": "12", "state": "Georgia"}' http://localhost:8080/webservices/REST/sample/loan
Returns:
Approved
For single inputs:
curl -H "Content-Type: application/json" -X POST -d "18" http://localhost:8080/webservices/REST/sample/age
Returns:
Approved
Using Spring Boot, tried to create a JUnit test, in order, to see if I can post to this external service using Spring's RestTemplate API.
public void RestWebServiceTest {
private RestTemplate restTemplate;
private HttpHeaders headers;
#Before
public void setup() {
restTemplate = new RestTemplate();
headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
}
#Test
public void validLoan() {
final String uri = "http://localhost:8080/webservices/REST/sample/Loan";
Map<String, String> input = new HashMap<>();
input.put("amount", "10000");
input.put("interestRate", ".28");
input.put("term", "12");
input.put("state", "Georgia");
String result = restTemplate.postForObject(uri, input, String.class);
assertEquals("Approved", result);
}
#Test
public void validAge() {
final String uri = "http://localhost:8080/webservices/REST/sample/age";
Integer input = 18;
String result = restTemplate.postForObject(uri, input, String.class);
assertEquals("Approved", result);
}
#Test
public void validCountry() {
final String uri = "http://localhost:8080/webservices/REST/sample/country
String input = "US";
String result = restTemplate.postForObject(uri, input, String.class);
assertEquals("Approved", result);
}
}
All of these work except for the validCountry() test method:
org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:641)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597)
This is strange because this curl command works for the same call:
curl -H "Content-Type: application/json" -X POST -d 'US' http://localhost:8080/webservices/REST/sample/country
Returns:
Approved
Question(s):
How can one mimic the rest call for the country (see above curl command) inside the validCountry() test method?
Do I need to add or change a different value for HTTP Headers (inside setup() method)?
Don't understand that validAge works by using the Integer wrapper class but the String doesn't?
Is there a better way to do this using Spring's RestTemplate API?
Thank you for taking the time to read this...

You need to set the Content-Type to application/json. Content-Type has to be set in request. Below is the modified code to set the Content-Type
#Test
public void validCountry() {
final String uri = "http://localhost:8080/webservices/REST/sample/country";
String input = "US";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<String>(input, headers);
String result = restTemplate.postForObject(uri, request, String.class);
assertEquals("Approved", result);
}
Here, HttpEntity is constructed with your input i.e "US" and with headers.
I think this answers you questions 1,2 and 4. But not 3.

Related

415 Error when authenticating - Spring boot and RestTemplate

I am working on a third-party REST API and I am going to authenticate with their API by making a POST request to the provided end point. I tested this end point using Postman and it works fine, and now I wanted to do it programmatically.
I am using Spring boot 3.0 for development and RestTemplate as the http client. The code I have implemented is below, it gives me a 415 UNSUPPORTED_MEDIA_TYPE error.
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==");
headers.add("Accept", "application/json");
headers.add("Content-Type","application/x-www-form-urlencoded");
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<String, String>();
requestBody.add("grant_type", "client_credentials");
HttpEntity formEntity = new HttpEntity<MultiValueMap<String, String>>(requestBody, headers);
String serverEndPoint = "https://xxxxxxx.xxx/auth/oauth2/xx/token";
ResponseEntity<String> response = restTemplate.exchange(serverEndPoint, HttpMethod.POST,formEntity, String.class);
System.out.println(response.getStatusCode().value());
Build RestTemplate
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
// don't throw
}
});
return restTemplate;
}
But same logic I have implemented using Jersey http client as mentioned below, it gives me successful response with 200 response code.
JacksonJsonProvider jacksonJsonProvider = new JacksonJaxbJsonProvider()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Client client = ClientBuilder.newClient(new ClientConfig(jacksonJsonProvider));
Form form = new Form();
form.param("grant_type", "client_credentials");
String serverEndPoint = "https://xxxxxxx.xxx/auth/oauth2/xx/token";
Response response = client.target(serverEndPoint)
.request("application/json")
.header("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==")
.post(Entity.entity(form, APPLICATION_FORM_URLENCODED));
System.out.println(response.getStatus());
Kindly help me to resolve this since I need to move forward with the RestTemplate client.
cUrl From Postman
curl --location --request POST 'https://xxxxxxxxxxxxx.xxx/auth/oauth2/xx/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==' \
--header 'Cookie: coolie data bla bla' \
--data-urlencode 'grant_type=client_credentials'
If I inspect what the successful calls (curl and the Jersey HttpClient) send to the server vs what RestTemplate.exchange() sends, the only significant difference is that RestTempate.exchange() appends the charset=utf-8 to the Content-Type header.
I suspect that the sever you are calling is too strict on Content-Type and throws a 415 if it does not match "application/x-www-form-urlencoded" exactly.
To prevent this you need to use RestTempate.postForObject() instead. Try changing your RestTemplate call code as follows:
String serverEndPoint = "https://httpbin.org/post";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> entity = new HttpEntity<>("grant_type=client_credentials", headers);
String result = restTemplate.postForObject( serverEndPoint, entity, String.class);
The MediaType is org.springframework.http.MediaType.
Note that I call httpbin.org in the code fragment. I find it extremely useful in researching an issue like this.

How can I pass parameter as post to endpoint using RestTemplate in springboot?

I am using RestTemplate in my project to make a post request to an endpoint. Basically I have lambda function written in nestjs. I am injecting lambda service in my java project. If vehicleName if condition passes, I would like to POST that vehicleName to the url. Is there any suggestions on how I can achieve this? I would be testing my application using this command
curl -X POST "https://gdxdispatcher.dev.awstrp.net/dispatcher/service/api/message" -H "accept: */*" -H "Content-Type: application/json" -d "{\"vehicleType\":\"US Mutual Fund,VIP\",\"source\":\"PCS_DATACACHE_TOPIC\"}"
Here is my code
private void callLambdaService(String vehicleTypesParamValue)
{
final String url = "http://localhost:3000/dispatcher/service/api/message";
final String zMETHOD = "callLambdaService - ";
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange("url", HttpMethod.POST, vehicleName, String.class);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String result = restTemplate.getForObject(url, String.class);
VehicleType vehicleName=null;
String[] vehicleTypes = vehicleTypesParamValue.split(",");
Set<VehicleType> results = new HashSet<>();
try
{
for (String vehicleTypeParam : vehicleTypes)
{
vehicleName =
vehicleTypeFactory.getVehicleTypeByIspName(
vehicleTypeParam);
if (vehicleName == null)
{
LOGGER.warn("No codes for products or vehicle types were supplied");
}
else if (vehicleName.equals("US Mutual Fund"))
{
LOGGER.info(zMETHOD + "Vehicles provided: "
+ vehicleName.getIspName());
}
else
{
LOGGER.warn(
String.format("Unknown vehicle type provided: [%s]",
vehicleName.getIspName()));
}
}
}catch (Exception e) {
LOG.error("Unable to get vehicletype data", e);
}
}
Well, following the instructions:
Create headers which will be a data structure representing HTTP request.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Build a JSONObject from org.json package that is a modifiable set of name/value mappings and put names and values.
JSONObject requestBody = new JSONObject();
requestBody.put("vehicleType", "US Mutual Fund,VIP");
requestBody.put("source", "PCS_DATACACHE_TOPIC");
Create our HttpEntity that represents an HTTP request or response, in this case request consisting of headers and body.
HttpEntity<String> request = new HttpEntity<>(requestBody.toString(), headers);
Create a new resource by posting an object to the given URI template.
It returns the result as automatically converted to the type specified in the responseType parameter.
Then we define a ObjectNode as our resource and response type as our result.
ObjectNode result = restTemplate.postForObject("https://gdxdispatcher.dev.awstrp.net/dispatcher/service/api/message",
request, ObjectNode.class);

POST request with form data using Spring RestTemplate

I have to make a HTTP POST request with form data to an external API. Currently, I am invoking the API using the below curl command
curl https://books.zoho.com/api/v3/contacts?organization_id=10234695
-X POST
-H "Authorization: Zoho-oauthtoken 216793f385b9dd6e125f"
-H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
-F 'JSONString="{
"contact_name": "Bowman and Co",
"company_name": "Bowman and Co",
"website": "www.bowmanfurniture.com",
"contact_type": "customer"
}
I have implemented ClientHttpRequestInterceptor interface and registered the interceptor with the RestTemplate. I am not sure, how to post the HTTP request with form data. Kindly let me know, how to submit the form data or point me to any reference.
Inside my Controller class:
#RestController
#RequestMapping("/api/v1/contacts")
public class ContactController {
#Autowired
private RestTemplate restTemplate;
#PostMapping("/")
public Invoice createContact(#RequestBody Contact contact){
//TODO
return null;
}
}
You could use a rest template to make a post request with form data.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("data", "data");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity<String> response = restTemplate.postForEntity( url, request , String.class );
Spring will automatically take care of the message converters used in this case.(The message converter used will be FormHttpMessageConverter).
Read Doc

Add Cookie parameter in Swagger UI documentation with Springfox

I want to add a #ApiImplicitParam Springfox annotation to document on Swagger UI a cookie, required by the service
#GetMapping(value = "cookies")
public void methodA(
#RequestHeader HttpHeaders headers) {
service.checkCookie(headers);
}
I'll try doing
#GetMapping(value = "cookies")
public void methodA(
#ApiImplicitParam(name="cookie", paramType = "header", type = "string") #RequestHeader HttpHeaders headers) {
service.checkCookie(headers);
}
But in Swagger UI don't sent any cookie when I push on Execute button.
Cookie isn't sent, and return a Bad Request 400 code. But If I execute the curl printed, I obtain an OK status.
curl -k -i -X GET "https://localhost:8080/cookies" -H "cookie: KEY=VALUE"
HTTP/1.1 200
Also try with paramType annotation value cookie like this:
#GetMapping(value = "cookies")
public void methodA(
#ApiImplicitParam(name="cookie", paramType = "cookie", type = "string") #RequestHeader HttpHeaders headers) {
service.checkCookie(headers);
}
With the same 400 error

HTTP POST using JSON in Spring Rest

I would like to make a simple HTTP POST using Spring RestTemplate.
the Wesb service accept JSON in parameter for example: {"name":"mame","email":"email#gmail.com"}
public static void main(String[] args) {
final String uri = "url";
RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// create request body
String input = "{ \"name\": \"name\", \"email\": \"email#gmail.com\" }";
JsonObject request = new JsonObject();
request.addProperty("model", input);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic " + "xxxxxxxxxxxx");
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> response = restTemplate
.exchange(uri, HttpMethod.POST, entity, String.class);
System.out.println(response);
}
When I test this code I got this error:
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 400 Bad Request
when I call webservice with Curl I have correct result:
curl -X POST -H "Authorization: Basic xxxxxxxxxx" --header "Content-Type: application/json" --header "Accept: application/json" -d "{ \"name\": \"name\", \"email\": \"email#gmail.com\" } " "url"
try to remove model from the code, as i can see in your curl request you didn't use model attribute and everything works. try this:
public static void main(String[] args) {
final String uri = "url";
RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// create request body
String input = "{\"name\":\"name\",\"email\":\"email#gmail.com\"}";
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic " + "xxxxxxxxxxxx");
HttpEntity<String> entity = new HttpEntity<String>(input, headers);
// send request and parse result
ResponseEntity<String> response = restTemplate
.exchange(uri, HttpMethod.POST, entity, String.class);
System.out.println(response);
}

Resources