From 28965a9623de75f4e7ee5d391fdbc9454b84e4a1 Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Fri, 16 Aug 2024 23:32:17 +0200 Subject: [PATCH] make API more robust Signed-off-by: Peter Siegmund --- .../fhq/timezone_service/Application.java | 6 ++--- .../timezone_service/config/AppConfig.java | 9 ++++++++ .../entities/response/IpifyResponse.java | 5 ++++ .../response/WorldTimeApiIpResponse.java | 6 +++-- .../timezone/service/TimeZoneService.java | 4 +++- .../service/impl/TimeZoneServiceImpl.java | 23 +++++++++++++++++-- .../web/controllers/TimeZoneController.java | 6 +++-- 7 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/IpifyResponse.java diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/Application.java b/src/main/java/dev/mars3142/fhq/timezone_service/Application.java index e4a3928..49b06f8 100644 --- a/src/main/java/dev/mars3142/fhq/timezone_service/Application.java +++ b/src/main/java/dev/mars3142/fhq/timezone_service/Application.java @@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } } diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/config/AppConfig.java b/src/main/java/dev/mars3142/fhq/timezone_service/config/AppConfig.java index da84b67..6654ad2 100644 --- a/src/main/java/dev/mars3142/fhq/timezone_service/config/AppConfig.java +++ b/src/main/java/dev/mars3142/fhq/timezone_service/config/AppConfig.java @@ -1,14 +1,23 @@ package dev.mars3142.fhq.timezone_service.config; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestClient; @Configuration +@EnableCaching public class AppConfig { @Bean public RestClient restClient() { return RestClient.create(); } + + @Bean + public CacheManager cacheManager() { + return new ConcurrentMapCacheManager(); + } } diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/IpifyResponse.java b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/IpifyResponse.java new file mode 100644 index 0000000..7035c88 --- /dev/null +++ b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/IpifyResponse.java @@ -0,0 +1,5 @@ +package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response; + +public record IpifyResponse(String ip) { + +} diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/WorldTimeApiIpResponse.java b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/WorldTimeApiIpResponse.java index 22f42a5..3aad215 100644 --- a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/WorldTimeApiIpResponse.java +++ b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/domain/entities/response/WorldTimeApiIpResponse.java @@ -1,7 +1,9 @@ package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response; -public record WorldTimeApiIpResponse(String utc_offset, String timezone, int day_of_week, int day_of_year, String datetime, +public record WorldTimeApiIpResponse(String utc_offset, String timezone, int day_of_week, int day_of_year, + String datetime, String utc_datetime, int unixtime, int raw_offset, int week_number, boolean dst, - String abbreviation, int dst_offset, String dst_from, String dst_until, String client_ip) { + String abbreviation, int dst_offset, String dst_from, String dst_until, + String client_ip) { } diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/TimeZoneService.java b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/TimeZoneService.java index d0f9ea1..238fc90 100644 --- a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/TimeZoneService.java +++ b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/TimeZoneService.java @@ -6,7 +6,9 @@ import java.util.List; public interface TimeZoneService { - WorldTimeApiIpResponse getTimeZoneInfoByIp(); + String getExternalIp(String ip); + + WorldTimeApiIpResponse getTimeZoneInfoByIp(String ip); TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone); diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/impl/TimeZoneServiceImpl.java b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/impl/TimeZoneServiceImpl.java index e28eb49..f91d775 100644 --- a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/impl/TimeZoneServiceImpl.java +++ b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/service/impl/TimeZoneServiceImpl.java @@ -1,6 +1,7 @@ package dev.mars3142.fhq.timezone_service.timezone.service.impl; import dev.mars3142.fhq.timezone_service.exceptions.NotFoundException; +import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.IpifyResponse; import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.TimeApiTimezoneZoneResponse; import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.WorldTimeApiIpResponse; import dev.mars3142.fhq.timezone_service.timezone.service.TimeZoneService; @@ -13,6 +14,7 @@ import java.util.Objects; import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import lombok.val; +import org.springframework.cache.annotation.Cacheable; import org.springframework.http.HttpStatusCode; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; @@ -24,15 +26,30 @@ public class TimeZoneServiceImpl implements TimeZoneService { private final RestClient restClient; @Override - public WorldTimeApiIpResponse getTimeZoneInfoByIp() { + public String getExternalIp(String ip) { + if (ip.equals("127.0.0.1")) { + val response = restClient + .get() + .uri("https://api.ipify.org?format=json") + .retrieve() + .body(IpifyResponse.class); + return Objects.requireNonNull(response).ip(); + } + return ip; + } + + @Override + @Cacheable(value = "TZInfoByIp", key = "{#ip}") + public WorldTimeApiIpResponse getTimeZoneInfoByIp(String ip) { return restClient .get() - .uri("https://worldtimeapi.org/api/ip") + .uri("https://worldtimeapi.org/api/ip/" + ip) .retrieve() .body(WorldTimeApiIpResponse.class); } @Override + @Cacheable(value = "TZInfo", key = "{#timezone}") public TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone) { return restClient .get() @@ -50,6 +67,7 @@ public class TimeZoneServiceImpl implements TimeZoneService { } @Override + @Cacheable(value = "posixTZ", key = "{#timezone}") public String getPosixTimeZone(String timezone) { val filename = Path.of("/usr/share/zoneinfo/" + timezone); if (!filename.toFile().exists()) { @@ -65,6 +83,7 @@ public class TimeZoneServiceImpl implements TimeZoneService { } @Override + @Cacheable(value = "locations", key = "{#area}") public List getLocations(String area) { val directory = new File("/usr/share/zoneinfo/" + area); if (!directory.exists()) { diff --git a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/web/controllers/TimeZoneController.java b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/web/controllers/TimeZoneController.java index 95984fd..9474be0 100644 --- a/src/main/java/dev/mars3142/fhq/timezone_service/timezone/web/controllers/TimeZoneController.java +++ b/src/main/java/dev/mars3142/fhq/timezone_service/timezone/web/controllers/TimeZoneController.java @@ -3,6 +3,7 @@ package dev.mars3142.fhq.timezone_service.timezone.web.controllers; import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.LocationResponse; import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.TimeZoneResponse; import dev.mars3142.fhq.timezone_service.timezone.service.TimeZoneService; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.web.bind.annotation.GetMapping; @@ -18,8 +19,9 @@ public class TimeZoneController { private final TimeZoneService timeZoneService; @GetMapping - public TimeZoneResponse getTimeZone() { - val timezoneInfo = timeZoneService.getTimeZoneInfoByIp(); + public TimeZoneResponse getTimeZone(HttpServletRequest request) { + val ip = timeZoneService.getExternalIp(request.getRemoteAddr()); + val timezoneInfo = timeZoneService.getTimeZoneInfoByIp(ip); val posix = timeZoneService.getPosixTimeZone(timezoneInfo.timezone()); return new TimeZoneResponse(timezoneInfo.timezone(), timezoneInfo.abbreviation(), posix); }