Spring data rest application backend notify frontend - java

Hi I would like to my backend (spring-data-rest) application to generate some sample data and notify frontend. However the repository event handler is REST only so I tried to write a restTemplate but failed.
#Scheduled(fixedRate = 5000)
public void addCounter() throws Exception {
String url = String.format("http://localhost:%d/%s/counters", 8080, api);
Counter counterExpected = new Counter('xxx', random.nextInt(100));
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(counterExpected);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(jsonString, headers);
restTemplate.postForObject(url, entity, String.class);
}
Error:
Description:
Field restTemplate in ScheduledTask required a bean of type 'org.springframework.boot.test.web.client.TestRestTemplate' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.boot.test.web.client.TestRestTemplate' in your configuration.
This error makes sense because I am using TestTestTemplate in my runtime application instead of test scope.
My questions are:
Is it possible to change the addCounter() method to something simpler just like:
counterRepository.save(newCounter);
/* Raise AfterCreate event */
If yes, then how?
If not then is there any other way to do a HTTP post instead of using restTemplate?

My bad. I should be using
import org.springframework.web.client.RestTemplate;
instead of
import org.springframework.boot.test.web.client.TestRestTemplate;

Related

Can we call external API without API ID?

I am new to API design, I am working on one project where I need to call currency exchange API from National Bank of Poland http://api.nbp.pl but I do not see any indication where I can find API ID. This development is on Spring Boot if I am trying to run the application without API ID it is throwing 404 error.
Here is the piece of code that I have written.
#RequestMapping(method = RequestMethod.GET, value = "/exchangerates/rates/{table}/{code}")
public #ResponseBody Object getAllCurriencyExchangeRates(#PathVariable String table, #PathVariable String code) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
ResponseEntity<Object> response =
restTemplate.getForEntity("http://api.nbp.pl/api/" +table+ "," +code+ Object.class, null, headers);
return response;
}
Actual query http://api.nbp.pl/api/exchangerates/rates/a/chf/
So, my question is can we call an external API without API ID?
First things first, you are trying to reach wrong API. That is why you are getting 404 not found. 404 means there is no url like you are calling.
Check your restTemplate carefully,
restTemplate.getForEntity("http://api.nbp.pl/api/" + table+ "," +code+ Object.class, null, headers);
You are doing wrong when concatenate strings.
It should look something like this;
restTemplate.getForEntity("http://api.nbp.pl/api/exchangerates/rates/"+table+"/"+code, Object.class, null, headers);
And a hint for API developers, firstly you should play with api using Postman and then write code with api.
Try this - I have tested it - it works. Please keep in mind this is just a test implementation. Things inside main method have to be copied into your getAllCurriencyExchangeRates method.
And for sure replace "a" and "chf" through variables. I assume table and code are the variables you want to use. I used String because I don't know which type of object you want to return. You can use your own pojo for sure instead of String.
package scripts;
import java.net.URI;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
/**
* author: flohall
* date: 08.12.19
*/
public class Test {
public static void main(final String[] args){
final String url = "http://api.nbp.pl/api/exchangerates/rates";
final URI uri = UriComponentsBuilder.fromHttpUrl(url).path("/").path("a").path("/").path("chf").build().toUri();
System.out.println(uri);
final RestOperations restTemplate = new RestTemplate();
final ResponseEntity<String> result = restTemplate.getForEntity(uri, String.class);
System.out.println(result.getBody());
}
}
Try with this
ResponseEntity<Object> response =
restTemplate.getForEntity("http://api.nbp.pl/api/exchangerates/rates/" + table + "/" + code, Object.class, headers);

RestTemplate exception no converters found while testing a Spring boot Application

I am new to testing world of spring boot application.
I want to do an integration testing on my Spring boot application. But i am getting following exception.
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 null
I am adding an employee and department into the in-memory database with bi-directional relationship.
public void testPostEmployee() throws Exception
{
System.out.println("Inside Post Employee method");
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
EmployeeTestDTO employeeTestDTO = new EmployeeTestDTO();
DepartmentTest departmentTest = new DepartmentTest(1,"Sales");
employeeTestDTO.setName("ABC");
employeeTestDTO.setAge(20);
employeeTestDTO.setSalary(1200.1);
employeeTestDTO.setDepartmentTest(departmentTest);
ObjectMapper objectMapper = new ObjectMapper();
String data = objectMapper.writeValueAsString(employeeTestDTO);
System.out.println(data);
HttpEntity<String> httpEntity = new HttpEntity<String>(data,httpHeaders);
ResponseEntity<?> postResponse = restTemplate.postForEntity(createURLWithPort("/employee"),
httpEntity,String.class);
Assert.assertEquals(201, postResponse.getStatusCodeValue());
}
This is my new edit. As per previously stated suggestion i tried to implement all of them but neither of them succeded. It gives the bad request 400 null exception. Please suggest me how to solve it
You should change ContentType from APPLICATION_FORM_URLENCODED to APPLICATION_JSON.
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
Also you need to add RestController:
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
#RestController
public class Controller {
#PostMapping("/employee")
#ResponseStatus(HttpStatus.CREATED)
public void getEmploee(#RequestBody EmployeeTestDTO employee) {
System.out.println(employee);
}
}

how to resolve 'HttpHeaders' has private access in 'org.apache.http.HttpHeaders' error

I am trying to make an Http Request using RestTemplate, and it keeps on giving me the error: 'HttpHeaders' has private access in 'org.apache.http.HttpHeaders'
I am simply trying to write this line:
HttpHeaders headers = new HttpHeaders();
The package name is wrong, in order to add headers when using Spring restTemplate, you should use org.springframework.http.HttpHeaders.HttpHeaders instead of org.apache.http.HttpHeaders.
The following is the code snippet that adds request headers.
// request resource
HttpHeaders headers = new HttpHeaders();
headers.set("headerName", "headerValue");
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<String> response = restTemplate.exchange("https://example.com", HttpMethod.GET, entity, String.class);
The constructor in org.apache.http.HttpHeaders is a private constructor - see source code clone {here}. Since you are trying to invoke a private attribute, that error message is expected.
Attaching relevant code snippet for posterity:
public final class HttpHeaders {
private HttpHeaders() {
}
// ....
// bunch of defined constants
// ....
}
The rationale behind this class is specified in the class docstring,
/**
* Constants enumerating the HTTP headers. All headers defined in RFC1945 (HTTP/1.0), RFC2616 (HTTP/1.1), and RFC2518
* (WebDAV) are listed.
*
* #since 4.1
*/
which is not the what you are trying to achieve here. If you wish to make a remote request, using apache library, with a request that contains headers, please follow {this example}. Adding relevant code snippet for posterity:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(SAMPLE_URL);
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
client.execute(request);
If you are using >=4.3 of HttpClient, you would want to do something like this:
HttpUriRequest request = RequestBuilder.get()
.setUri(SAMPLE_URL)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.build();
To remove compilation errors with
HttpHeaders headers = new HttpHeaders();
make sure you haven't imported HttpHeaders from apache http clients.
import org.apache.http.HttpHeaders;
this will not work as HttpHeaders has a private constructor.
Your import statement should be this:
import org.springframework.http.HttpHeaders;
And then you can add headers using the add(String headerName, String headerValue) method.
Source: Link

How to consume a HTTPS GET service with Spring Boot

I am trying to consume the following HTTPS endpoints from Yahoo Weather Service:
Yahoo Weather Service API
I am doing some special query according to the API to get the current weather at some parametrized location.
#Service("weatherConditionService")
public class WeatherConditionServiceImpl implements WeatherConditionService {
private static final String URL = "http://query.yahooapis.com/v1/public/yql";
public WeatherCondition getCurrentWeatherConditionsFor(Location location) {
RestTemplate restTemplate = new RestTemplate();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(URL);
stringBuilder.append("?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22");
// TODO: Validate YQL query injection
stringBuilder.append(location.getName());
stringBuilder.append("%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys");
WeatherQuery weatherQuery = restTemplate.getForObject(stringBuilder.toString(), WeatherQuery.class);
// TODO: Test Json mapping response
Condition condition = weatherQuery.getQuery().getResults().getChannel().getItem().getCondition();
return new WeatherCondition(condition.getDate(), Integer.parseInt(condition.getTemp()), condition.getText());
}
Location is a class that provides the attribute "name" that is a String description of the location, such as "New York" or "Manila".
Condition an other classes just map the returning object.
When executing I get the following HTTP response:
org.springframework.web.client.HttpClientErrorException: 403 Forbidden
So this means I am not authorized to access the resource from what I understand.
The URL works great if I just copy & paste it in a web browser:
Yahoo Weather Query
I think that mapping is not a problem since I am not getting "400" (Bad Request) but "403" (Forbidden)
There must be some error on the way I use the RestTemplate object. I am researching but I can't find an answer.
The docs say you need an api key. But when I make a call like this:
fetch('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys')
.then(resp=> resp.json())
.then((res)=>console.log(res.query.results))
https://repl.it/NeoM
It works fine without one. Perhaps you've been blackisted for hitting the api too often.
Your code seems fine.
I finally found the answer. It finally WAS a Bad Request because I needed to pass the parameters differently (not as part of the URL).
I found the answer here. Here goes the code for my particular Yahoo Weather API call return a String (I still will have to do some work to use the mapping).
private static final String URL = "http://query.yahooapis.com/v1/public/yql";
public String callYahooWeatherApi() {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(URL)
.queryParam("q", "select wind from weather.forecast where woeid=2460286")
.queryParam("format", "json");
HttpEntity<?> entity = new HttpEntity<>(headers);
HttpEntity<String> response = restTemplate.exchange(
builder.build().encode().toUri(),
HttpMethod.GET,
entity,
String.class);
return response.getBody();
}

Spring for Android - Could not extract response: no suitable HttpMessageConverter found for response type

I'm trying to retrieve some data from a REST service using spring for Android.
However I'm running into problems. I'm also using Robospice - and as such have a method like so:
public FunkyThingsList loadDataFromNetwork() throws Exception {
String baseURI =context.getResources().getString(R.string.baseWebServiceURI);
String uri = baseURI + "/FunkyThings/date/" + dateToLookUp.toString("yyyy-MM-dd");
RestTemplate restTemplate = getRestTemplate();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setAccept( Arrays.asList(MediaType.APPLICATION_JSON));
HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
headers.setAuthorization(authHeader);
// Create the request body as a MultiValueMap
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
HttpMessageConverter<String> stringConverter = new StringHttpMessageConverter();
FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
List<HttpMessageConverter<?>> msgConverters = restTemplate.getMessageConverters();
msgConverters.add(formConverter);
msgConverters.add(stringConverter);
restTemplate.setMessageConverters(msgConverters);
HttpEntity<?> httpEntity = new HttpEntity<Object>(map, headers);
final ResponseEntity<FunkyThingsList> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity,FunkyThingsList.class);
return responseEntity.getBody();
}
Unfortunately this isn't working. I'm getting the following exception thrown:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.MyProject.DataClassPojos.RoboSpiceArrayLists.FunkyThingsList] and content type [application/json;charset=utf-8]
Now based on my Googling I get the feeling I need to add a message converter. I'm just not sure which message converter I need, or where I add it?
For the default JSON HttpMessageConverter, you'll need to add either Jackson 1 or Jackson 2 to your classpath.
Otherwise, you can add some other JSON library and write your own HttpMessageConverter which can do the deserialization. You add it to the RestTemplate. You can either use the constructor or this method.
If you are following the Spring for Android tutorial and you get the same error - this might be of help:
In your MainActivity.java:
...
RestTemplate restTemplate = new RestTemplate();
MappingJacksonHttpMessageConverter converter = new
MappingJacksonHttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_HTML));
restTemplate.getMessageConverters().add(converter);
Use the converter in the call and configure it to use as a Media Type the TEXT_HTML, then use the instance of the converter.
Also the tutorial is a bit outdated so use the latest versions as suggested here in your build.gradle:
dependencies{
//Spring Framework for REST calls and Jackson for JSON processing
compile 'org.springframework.android:spring-android-rest-template:2.0.0.M3'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.1.3'
}
repositories {
maven {
url 'https://repo.spring.io/libs-milestone'
}
}

Categories