I am very new to Spring and I am having trouble getting anything back from a rest service. I would love to get an answer to what I am doing wrong. Thanks in an advance!
This is the rest service from where I am trying to get an answer:
Here is my code.
package testi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
#SpringBootApplication
public class TestiApplication {
public static void main(String[] args) {
SpringApplication.run(TestiApplication.class, args);
}
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
//Asetettaan otsikkotietueet
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("X-ESA-API-KEY", "ROBOT");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
System.out.println("Testing " + entity.getHeaders());
String answer = restTemplate.postForObject("https://www.veikkaus.fi/api/v1/sport-games/draws?game-names=MULTISCORE", entity, String.class);
System.out.println(answer);
//ResponseEntity<String> response = restTemplate.exchange("https://www.veikkaus.fi/api/v1/sport-games/draws?game-names=MULTISCORE", HttpMethod.GET, entity, String.class);
//System.out.println(response);
}
}
The API documentation you provided seems to indicate the API you're trying to access uses the GET method. You are making the request with the POST method (restTemplate.postForObject(...)).
Try using the GET method via restTemplate.getForObject(...).
In general, when debugging your REST calls, you should also examine the response status code in addition to the response body. In this case this arguably would have yielded the HTTP 405 error indicating what went wrong.
Related
I'm trying to learn a bit of Java and readthe documentation for the httpClient method since I'm trying to make a call to an endpoint created with Soap UI.
I'm just trying to obtain a response the JSON object but for some reason I keep getting an empty response and a 404 status code. I've been tinkering with it a bit but I can't seem to find the problem.
Here's my code
package org.example;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class App {
private static final String GET_API_URL = "http://localhost:8080/balance?acctnum=1234567";
public static void main( String[] args ) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.header( "accept", "application/json")
.uri(URI.create(GET_API_URL))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("status:" + response.statusCode());
System.out.println("response:" + response.body());
}
}
both the system.out are being hit but as mentioned the first one returns status 404 and the second one returns "response: ".
Any suggestions?
I am using some external API to GET and POST some ressources, locally my code works fine with the call of different endPoints (GET, POST...) and even with Postman, but when i try to run my code in another platerform (where the ressources are), i get the 412 HTTP error due to a POST call : after looking on the internet, i found out that i should generate an ETagd of the entity (that i went to modify) and add it into the header of my POST endPoint.
For that, i used ShallowEtagHeaderFilter and the #Bean annotation(above the filter method) and the #SpringBootApplication annotation above my class, here is my code :
package main.Runners;
import io.testproject.java.annotations.v2.Parameter;
import okhttp3.*;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.configurationprocessor.json.JSONArray;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import javax.servlet.Filter;
#SpringBootApplication
public class ActionRunner {
#Parameter(description = "the project ID")
public static String projectId = "xxx";
#Parameter(description = "the test ID")
public static String testId = "yyy";
public static void main(String[] args) throws Exception {
try {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url("https://api.testproject.io/v2/projects/"+projectId+"/tests/"+testId)
.method("GET", null)
.addHeader("Authorization", "nzmo4DI08ykizYgcp9-5cCTArlxq7k7zt9MYhGmTcRk1")
.build();
Response response = client.newCall(request).execute();
System.out.println("================ this is our response headers ::: \n"+ response.headers());
} catch(Exception e) {
System.out.println(e);
}
}
#Bean
public ShallowEtagHeaderFilter shallowEtagHeaderFilter(){
return new ShallowEtagHeaderFilter();
}
}
I really need Your help since i cant generate any ETag parameter on my GET response header(after checking reponse.headers() ).
Thanks in advance!
Say that Java application makes requests to http://www.google.com/... and there's no way to configure the inherited library (making such requests internally), so I can not stub or replace this URL.
Please, share some best practices to create a mock like
whenCalling("http://www.google.com/some/path").withMethod("GET").thenExpectResponse("HELLO")
so a request made by any HTTP client to this URL would be redirected to the mock and replaced with this response "HELLO" in the context of current JVM process.
I tried to find a solution using WireMock, Mockito or Hoverfly, but it seems that they do something different from that. Probably I just failed to use them properly.
Could you show a simple set up from the main method like:
create mock
start mock simulation
make a request to the URL by an arbitrary HTTP client (not entangled with the mocking library)
receive mocked response
stop mock simulation
make the same request as on step 3
receive real response from URL
Here's how to achieve what you want with the API Simulator.
The example demonstrates two different ways to configure Embedded API Simulator as HTTP proxy for the Spring's RestTemplate client. Check with the documentation of the (quote from the question) "inherited library" - often times Java-based clients rely on system properties described here or may offer some way to configure HTTP proxy with code.
package others;
import static com.apisimulator.embedded.SuchThat.*;
import static com.apisimulator.embedded.http.HttpApiSimulation.*;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.URI;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import com.apisimulator.embedded.http.JUnitHttpApiSimulation;
public class EmbeddedSimulatorAsProxyTest
{
// Configure an API simulation. This starts an instance of
// Embedded API Simulator on localhost, default port 6090.
// The instance is automatically stopped when the test ends.
#ClassRule
public static final JUnitHttpApiSimulation apiSimulation = JUnitHttpApiSimulation
.as(httpApiSimulation("my-sim"));
#BeforeClass
public static void beforeClass()
{
// Configure simlets for the API simulation
// #formatter:off
apiSimulation.add(simlet("http-proxy")
.when(httpRequest("CONNECT"))
.then(httpResponse(200))
);
apiSimulation.add(simlet("test-google")
.when(httpRequest()
.whereMethod("GET")
.whereUriPath(isEqualTo("/some/path"))
.whereHeader("Host", contains("google.com"))
)
.then(httpResponse()
.withStatus(200)
.withHeader("Content-Type", "application/text")
.withBody("HELLO")
)
);
// #formatter:on
}
#Test
public void test_using_system_properties() throws Exception
{
try
{
// Set these system properties just for this test
System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", "6090");
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("http://www.google.com/some/path");
ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
Assert.assertEquals(200, response.getStatusCode().value());
Assert.assertEquals("HELLO", response.getBody());
}
finally
{
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
}
}
#Test
public void test_using_java_net_proxy() throws Exception
{
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// A way to configure API Simulator as HTTP proxy if the HTTP client supports it
Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress("localhost", 6090));
requestFactory.setProxy(proxy);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(requestFactory);
URI uri = new URI("http://www.google.com/some/path");
ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
Assert.assertEquals(200, response.getStatusCode().value());
Assert.assertEquals("HELLO", response.getBody());
}
#Test
public void test_direct_call() throws Exception
{
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("http://www.google.com");
ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
Assert.assertEquals(200, response.getStatusCode().value());
Assert.assertTrue(response.getBody().startsWith("<!doctype html>"));
}
}
When using maven, add the following to project's pom.xml to include the Embedded API Simulator as a dependency:
<dependency>
<groupId>com.apisimulator</groupId>
<artifactId>apisimulator-http-embedded</artifactId>
<version>1.6</version>
</dependency>
... and this to point to the repository:
<repositories>
<repository>
<id>apisimulator-github-repo</id>
<url>https://github.com/apimastery/APISimulator/raw/maven-repository</url>
</repository>
</repositories>
I'm trying to find a way to retrieve the URL that is currently mapped by Feign Client method interface in a Spring app, but I could not find a solution yet. The following code works:
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
application.yml
api:
url: https://jsonplaceholder.typicode.com
ApiClient.class
package com.example.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
#FeignClient(name = "json-placeholder", url = "${api.url}")
public interface ApiClient {
#GetMapping(value = "/posts", consumes = "application/json")
ResponseEntity<String> getPosts();
}
FeignApplication.class
package com.example.feign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import javax.annotation.PostConstruct;
#EnableFeignClients
#SpringBootApplication
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
#Autowired
private ApiClient apiClient;
#PostConstruct
public void test() {
// this works
System.out.println(apiClient.getPosts().getBody());
// apiClient. ... getPosts request URL
}
}
I tried to compose this URL reading directly from annotations, but it doesn't seem to work. Can anybody give me an alternative? Thank you.
EDIT notes -
Sorry, but I had do a small change in my question, due to an unexpected problem while applying provided solutions.
Reading directly from Annotations works if the value set in annotation property is literal. If the value is read from application.yml file, the URL returned by the annotation property is the expression ifself, not the parsed value.
Any ideas about this updated scenario? What I need is the URL actually been called by FeignClient. I'm understands all provided solutions are actually workarounds.
I'm not sure if you are still looking for the answer, but my method is below
Return Response
import feign.Response;
#FeignClient(name = "json-placeholder", url = "${api.url}")
public interface ApiClient {
#GetMapping(value = "/posts", consumes = "application/json")
Response getPosts();
}
get Request.url from the Response
Response response = apiClient.getPosts();
String url = response.request().url()
then you can get the URL
From this artcle, I have implemented calling another rest API from my REST API method in micronaut gradle application. Since my REST API expects jwt token I am sending the same token I received with in current request. I am seeing Unauthorized error even token is being passed. Can anyone help in this regard. Below is my code.
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpStatus;
import io.appter.clientmgmt.models.ClientContact;
import io.appter.clientmgmt.repositories.IClientContactRepository;
import io.micronaut.http.uri.UriTemplate;
import io.micronaut.security.annotation.Secured;
import io.micronaut.security.authentication.Authentication;
import io.micronaut.security.rules.SecurityRule;
import io.micronaut.http.annotation.*;
import io.micronaut.http.client.RxHttpClient;
import io.micronaut.http.client.annotation.Client;
import io.reactivex.Flowable;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import javax.validation.constraints.NotNull;
import java.security.Security;
import java.util.List;
#Controller("/clientcontact")
//#Secured(SecurityRule.IS_ANONYMOUS)
public class ClientContactController {
private static final Logger LOG = LoggerFactory.getLogger(ClientContactController.class);
private IClientContactRepository clientContactRepository;
private final RxHttpClient httpClient;
public ClientContactController(IClientContactRepository clientContactRepository,
#Client("http://appterauthsvc-env.g2yapp2kcp.us-east-1.elasticbeanstalk.com") RxHttpClient httpClient) {
this.clientContactRepository = clientContactRepository;
this.httpClient = httpClient;
}
#Get("/")
public HttpStatus index() {
return HttpStatus.OK;
}
#Post("/")
#Secured(SecurityRule.IS_AUTHENTICATED)
public ClientContact createClientContact(#Body ClientContact clientContact,
Authentication authentication,
#Header("Authorization") String authorization) {
try {
List<ClientContact> existingClientContacts = clientContactRepository.getClientContactByClientId(clientContact.getClientId());
LOG.info("current contacts count for the client " + clientContact.getClientId() + " is " + existingClientContacts.size());
if (existingClientContacts.isEmpty()) {
User userObj = new User();
Long clientId = new Long(clientContact.getClientId());
userObj.setClientId(clientId);
userObj.setFirstName(clientContact.getFirstName());
userObj.setLastName(clientContact.getLastName());
userObj.setEmailId(clientContact.getEmailAddress());
userObj.setPhoneNo(clientContact.getContactNumber());
userObj.setIsActive(true);
LOG.info("User Email set is: "+userObj.getEmailId());
LOG.info("authorization token is: "+authorization);
HttpRequest<?> request = HttpRequest.POST("/user", userObj).bearerAuth(authorization);
String response = httpClient.toBlocking().retrieve(request);
LOG.info("Request Object: "+ request.toString());
LOG.info("Response Object: "+ response.toString());
LOG.info("User API executed.. ");
}
return clientContactRepository.createClientContact(clientContact);
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
return null;
}
}
}
Thanks in advance.
Likely because #Header("Authorization") String authorization is returning something like Bearer xyz... and the bearerAuth method is adding Bearer to the string so you are sending Bearer Bearer xyz...
So just do .header(HttpHeaders.AUTHORIZATION, authorization)
Also as a side note you really shouldn't be doing blocking HTTP calls in this method. It's not the end of the world since in this case you're blocking an IO thread, however this type of code should be avoided.