RestTemplate and Java 17 Records
As part of my ongoing solar project I wanted some basic weather forecast information to help make judgements around cloud coverage. The good people at OpenWeather provide an api with a free tier that includes forecasted cloud coverage data hourly for a couple of days.
The api returns a JSON structure that looks like this :
{
"lat": 50.8,
"lon": 0.027,
"timezone": "Europe/London",
"timezone_offset": 0,
"current": {
"dt": 1644836705,
"sunrise": 1644822797,
"sunset": 1644858426,
"temp": 281.32,
"feels_like": 277.84,
"pressure": 997,
"humidity": 80,
"dew_point": 278.08,
"uvi": 0.98,
"clouds": 75,
"visibility": 10000,
"wind_speed": 6.69,
"wind_deg": 250,
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
]
},
"hourly": [
{
"dt": 1644836400,
"temp": 281.32,
"feels_like": 277.47,
"pressure": 997,
"humidity": 80,
"dew_point": 278.08,
"uvi": 0.98,
"clouds": 75,
"visibility": 10000,
"wind_speed": 7.9,
"wind_deg": 242,
"wind_gust": 12.16,
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
],
"pop": 0.05
},
.
.
.
With 48 of those hourly snippets covering the next two days.
I’ve previously been a big proponent of Project Lombok for dealing with lots of record type classes, but I’ve a free hand with this project so I’m able to use Java 17 and the record classes.
The record definitions are as follows :
public record Weather(int id,String main,String description,String icon)
{}
public record Prediction(long dt, double temp, double feels_like, int pressure, int humidity, double dew_point,
double uvi, int clouds, int visibility, double wind_speed, int wind_deg, double wind_gust,
Weather[] weather, double pop)
{}
public record Forecast(double lat, double lon, String timezone, String timezone_offset, Prediction current,
Prediction[] hourly)
{}
Using RestTemplate, getting the data is as simple as :
private RestTemplate restTemplate = new RestTemplate();
@GetMapping(value = "/cloudcover", produces = { MediaType.APPLICATION_JSON_VALUE})
public List<CloudCover> cloudcover(@RequestParam String lat, @RequestParam String lon, @RequestParam String apiToken) throws URISyntaxException
{
final String baseUrl = String.join(
"",
"https://api.openweathermap.org/data/2.5/onecall?lat=",
lat,
"&lon=",
lon,
"&exclude=daily,alerts,minutely&appid=",
apiToken
);
URI uri = new URI(baseUrl);
ResponseEntity<Forecast> data = restTemplate.getForEntity(uri, Forecast.class);
Now data.getBody()
returns the structure defined by the records.
The reason I’m writing this up, is I’m hugely impressed by the increase in productivity the combination of Records and the Spring RestTemplate have made consuming services like this. Within 10 minutes I had a service able to pull the data from OpenWeather.