make API more robust
Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
@@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class Application {
|
public class Application {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(Application.class, args);
|
SpringApplication.run(Application.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +1,23 @@
|
|||||||
package dev.mars3142.fhq.timezone_service.config;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.client.RestClient;
|
import org.springframework.web.client.RestClient;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RestClient restClient() {
|
public RestClient restClient() {
|
||||||
return RestClient.create();
|
return RestClient.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CacheManager cacheManager() {
|
||||||
|
return new ConcurrentMapCacheManager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response;
|
||||||
|
|
||||||
|
public record IpifyResponse(String ip) {
|
||||||
|
|
||||||
|
}
|
@@ -1,7 +1,9 @@
|
|||||||
package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response;
|
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 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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,9 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface TimeZoneService {
|
public interface TimeZoneService {
|
||||||
|
|
||||||
WorldTimeApiIpResponse getTimeZoneInfoByIp();
|
String getExternalIp(String ip);
|
||||||
|
|
||||||
|
WorldTimeApiIpResponse getTimeZoneInfoByIp(String ip);
|
||||||
|
|
||||||
TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone);
|
TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone);
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package dev.mars3142.fhq.timezone_service.timezone.service.impl;
|
package dev.mars3142.fhq.timezone_service.timezone.service.impl;
|
||||||
|
|
||||||
import dev.mars3142.fhq.timezone_service.exceptions.NotFoundException;
|
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.TimeApiTimezoneZoneResponse;
|
||||||
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.WorldTimeApiIpResponse;
|
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.WorldTimeApiIpResponse;
|
||||||
import dev.mars3142.fhq.timezone_service.timezone.service.TimeZoneService;
|
import dev.mars3142.fhq.timezone_service.timezone.service.TimeZoneService;
|
||||||
@@ -13,6 +14,7 @@ import java.util.Objects;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.http.HttpStatusCode;
|
import org.springframework.http.HttpStatusCode;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestClient;
|
import org.springframework.web.client.RestClient;
|
||||||
@@ -24,15 +26,30 @@ public class TimeZoneServiceImpl implements TimeZoneService {
|
|||||||
private final RestClient restClient;
|
private final RestClient restClient;
|
||||||
|
|
||||||
@Override
|
@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
|
return restClient
|
||||||
.get()
|
.get()
|
||||||
.uri("https://worldtimeapi.org/api/ip")
|
.uri("https://worldtimeapi.org/api/ip/" + ip)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.body(WorldTimeApiIpResponse.class);
|
.body(WorldTimeApiIpResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Cacheable(value = "TZInfo", key = "{#timezone}")
|
||||||
public TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone) {
|
public TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone) {
|
||||||
return restClient
|
return restClient
|
||||||
.get()
|
.get()
|
||||||
@@ -50,6 +67,7 @@ public class TimeZoneServiceImpl implements TimeZoneService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Cacheable(value = "posixTZ", key = "{#timezone}")
|
||||||
public String getPosixTimeZone(String timezone) {
|
public String getPosixTimeZone(String timezone) {
|
||||||
val filename = Path.of("/usr/share/zoneinfo/" + timezone);
|
val filename = Path.of("/usr/share/zoneinfo/" + timezone);
|
||||||
if (!filename.toFile().exists()) {
|
if (!filename.toFile().exists()) {
|
||||||
@@ -65,6 +83,7 @@ public class TimeZoneServiceImpl implements TimeZoneService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Cacheable(value = "locations", key = "{#area}")
|
||||||
public List<String> getLocations(String area) {
|
public List<String> getLocations(String area) {
|
||||||
val directory = new File("/usr/share/zoneinfo/" + area);
|
val directory = new File("/usr/share/zoneinfo/" + area);
|
||||||
if (!directory.exists()) {
|
if (!directory.exists()) {
|
||||||
|
@@ -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.LocationResponse;
|
||||||
import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.TimeZoneResponse;
|
import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.TimeZoneResponse;
|
||||||
import dev.mars3142.fhq.timezone_service.timezone.service.TimeZoneService;
|
import dev.mars3142.fhq.timezone_service.timezone.service.TimeZoneService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@@ -18,8 +19,9 @@ public class TimeZoneController {
|
|||||||
private final TimeZoneService timeZoneService;
|
private final TimeZoneService timeZoneService;
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public TimeZoneResponse getTimeZone() {
|
public TimeZoneResponse getTimeZone(HttpServletRequest request) {
|
||||||
val timezoneInfo = timeZoneService.getTimeZoneInfoByIp();
|
val ip = timeZoneService.getExternalIp(request.getRemoteAddr());
|
||||||
|
val timezoneInfo = timeZoneService.getTimeZoneInfoByIp(ip);
|
||||||
val posix = timeZoneService.getPosixTimeZone(timezoneInfo.timezone());
|
val posix = timeZoneService.getPosixTimeZone(timezoneInfo.timezone());
|
||||||
return new TimeZoneResponse(timezoneInfo.timezone(), timezoneInfo.abbreviation(), posix);
|
return new TimeZoneResponse(timezoneInfo.timezone(), timezoneInfo.abbreviation(), posix);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user