Skip to content

Commit

Permalink
added weather api
Browse files Browse the repository at this point in the history
  • Loading branch information
SamuelSlavka committed Nov 10, 2024
1 parent b9a06b4 commit 0e2fa2e
Show file tree
Hide file tree
Showing 15 changed files with 412 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ build/

### VS Code ###
.vscode/

logs.log*
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
<artifactId>modelmapper</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.backend.api.scheduled.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
@EnableScheduling
@ComponentScan(basePackages = "tasks")
public class SchedulingConfig {
@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.backend.api.scheduled.controller;

import com.backend.api.scheduled.entity.Forecast;
import com.backend.api.scheduled.entity.Weather;
import com.backend.api.scheduled.service.ApiService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Controller for weather and stocks
*/
@RestController
@RequestMapping(path = "/api/v1/scheduled")
public class ScheduledController {
private final Logger logger = LoggerFactory.getLogger((ScheduledController.class));

@Autowired
private ApiService apiService;

/**
* Get endpoint that fetches current weather
*
* @return returns body of HTTP response with Weather
*/
@GetMapping(path = "/weather")
public Weather getWeather() {
this.logger.info("Fetching weather");
return apiService.getLatestWeather();
}

/**
* Get endpoint that fetches current forecast
*
* @return returns body of HTTP response with Forecast
*/
@GetMapping(path = "/forecast")
public Forecast getForecast() {
this.logger.info("Fetching forecast");
return apiService.getLatestForecast();
}

/**
* Get endpoint that fetches current stocks
*
* @return returns body of HTTP response with StocksTicker
*/
@GetMapping(path = "/stocks")
public String getStocks() {
this.logger.info("Fetching stocks");
return apiService.getLatestStocks();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.backend.api.scheduled.cosntants;

public class Constants {
public final static String forecastBaseUrl = "https://api.openweathermap.org/data/2.5/forecast?lat=50.07&lon=14.43";
public final static String weatherBaseUrl = "https://api.openweathermap.org/data/2.5/weather?lat=50.07&lon=14.43";
public final static String stocksBaseUrl = "https://api.openweathermap.org/data/3.0/onecall?lat={lat}&lon={lon}";
public final static Long weatherId = 0L;
public final static Long forecastId = 1L;
}
32 changes: 32 additions & 0 deletions src/main/java/com/backend/api/scheduled/entity/Forecast.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.backend.api.scheduled.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Entity
@Table(name = "forecast")
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Forecast {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Setter
@Getter
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "forecast_id")
@JsonProperty("list")
private List<Weather> list;
}
84 changes: 84 additions & 0 deletions src/main/java/com/backend/api/scheduled/entity/Weather.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.backend.api.scheduled.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import com.fasterxml.jackson.annotation.JsonFormat;

import java.time.LocalDateTime;
import java.util.List;

@Entity
@Table(name = "weather")
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Weather {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "forecast_id")
@JsonIgnore
private Forecast forecast;

@Embedded
@JsonProperty("main")
private Main main;

@Embedded
@JsonProperty("sys")
private Sys sys;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "weather_id")
@JsonProperty("weather")
private List<WeatherDescription> weatherInner;

@Setter
@Getter
@JsonProperty("dt_txt")
@Column(name = "dt_txt")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dtTxt;

@Embeddable
@Setter
@Getter
public static class Main {
@JsonProperty("temp")
private Double temp;

@JsonProperty("temp_max")
private Double temp_max;

@JsonProperty("temp_min")
private Double temp_min;

@JsonProperty("feels_like")
private Double feels_like;

@JsonProperty("humidity")
private Double humidity;
}


@Embeddable
@Setter
@Getter
public static class Sys {
@JsonProperty("sunrise")
private String sunrise;

@JsonProperty("sunset")
private String sunset;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.backend.api.scheduled.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Setter
@Getter
@Embeddable
@Table(name = "weather_description")
public class WeatherDescription {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@JsonProperty("main")
private String main;

@JsonProperty("description")
private String description;

@JsonProperty("icon")
private String icon;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.backend.api.scheduled.repository;

import com.backend.api.scheduled.entity.Forecast;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface ForecastRepository extends JpaRepository<Forecast, String> {
Optional<Forecast> findById(Long s);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.backend.api.scheduled.repository;

import com.backend.api.scheduled.entity.Weather;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface WeatherRepository extends JpaRepository<Weather, String> {
void deleteByForecastId(Long forecastId);

Weather findByForecastId(Long forecastId);
}
21 changes: 21 additions & 0 deletions src/main/java/com/backend/api/scheduled/service/ApiService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.backend.api.scheduled.service;

import com.backend.api.scheduled.entity.Forecast;
import com.backend.api.scheduled.entity.Weather;

/**
* Service used for calling external apis
*/
public interface ApiService {
void callStocksApi();

String getLatestStocks();

void callWeatherApi();

Weather getLatestWeather();

void callForecastApi();

Forecast getLatestForecast();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.backend.api.scheduled.service;

import com.backend.api.scheduled.cosntants.Constants;
import com.backend.api.scheduled.entity.Forecast;
import com.backend.api.scheduled.entity.Weather;
import com.backend.api.scheduled.repository.ForecastRepository;
import com.backend.api.scheduled.repository.WeatherRepository;
import jakarta.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Optional;

@Service
public class ApiServiceImpl implements ApiService {

private static final Logger logger = LoggerFactory.getLogger(ApiServiceImpl.class);

@Value("${OPEN_WEATHER_API}")
private String weatherApiKey;

@Value("${ALPHA_VANTAGE_API}")
private String alphaApiKey;

@Autowired
private ForecastRepository forecastRepository;

@Autowired
private WeatherRepository weatherRepository;

@Override
@Transactional
public void callStocksApi() {
logger.info("StocksTask executed");
}

public String getLatestStocks() {
return "";
}

@Override
@Transactional
public void callWeatherApi() {
String weatherUrl = String.format("%s&appid=%s&units=metric", Constants.weatherBaseUrl, weatherApiKey);
RestTemplate restTemplate = new RestTemplate();
Weather weatherResponse = restTemplate.getForObject(weatherUrl, Weather.class);
Optional<Forecast> forecast = forecastRepository.findById(Constants.weatherId);
if (weatherResponse != null && forecast.isPresent()) {
weatherRepository.deleteByForecastId(Constants.weatherId);
weatherResponse.setForecast(forecast.get());
weatherRepository.save(weatherResponse);
logger.info("Weather updated");
}
logger.info("Weather Task executed");
}

public Weather getLatestWeather() {
Optional<Forecast> fr = forecastRepository.findById(Constants.weatherId);
return fr.map(forecast -> forecast.getList().get(0)).orElse(null);
}

@Override
@Transactional
public void callForecastApi() {
String forecastUrl = String.format("%s&appid=%s&units=metric", Constants.forecastBaseUrl, weatherApiKey);
RestTemplate restTemplate = new RestTemplate();
Forecast forecastResponse = restTemplate.getForObject(forecastUrl, Forecast.class);
if (forecastResponse != null) {
forecastResponse.setId(Constants.forecastId);
weatherRepository.deleteByForecastId(Constants.forecastId);
forecastRepository.save(forecastResponse);
logger.info("Forecast updated");
}
logger.info("Forecast Task executed");
}

public Forecast getLatestForecast() {
Optional<Forecast> fr = forecastRepository.findById(Constants.forecastId);
return fr.orElse(null);
}
}
Loading

0 comments on commit 0e2fa2e

Please sign in to comment.