Cześć, mój kod ma za zadanie pobrać współrzędne dla lokalizacji podanej przez użytkownika i zapisanie ich w bazie danych. Nie będę wrzucał całego kodu oto najważniejsze części:
1.ApiClient
@Component
@Slf4j
public class LocationApiClient {
private final String API_KEY;
private final Duration timeout = Duration.ofSeconds(5);
private final WebClient webClient;
@Autowired
public LocationApiClient(@Qualifier("location") WebClient webClient,
@Value("${WEATHER_API_KEY}") String API_KEY) {
this.webClient = webClient;
this.API_KEY = API_KEY;
}
public LocationRequest fetchGeocodingData(String locationName) {
try {
return webClient.get()
.uri(uriBuilder -> uriBuilder
.queryParam("q", locationName)
.queryParam("appid", API_KEY)
.build())
.exchangeToFlux(clientResponse -> {
HttpStatusCode status = clientResponse.statusCode();
if (status.equals(HttpStatus.TOO_MANY_REQUESTS)) {
log.error("Exceeded number of allowed calls to Geocoding API. Please try again later: {}",
clientResponse.statusCode());
return Flux.error(new TooManyRequestsException(
"Exceeded number of allowed calls to Geocoding API. Please try again later."));
} else if (status.equals(HttpStatus.UNAUTHORIZED)) {
log.error("Invalid authorization token");
return Flux.error(new AuthorizationException("Invalid authorization token"));
} else if (status.equals(HttpStatus.SERVICE_UNAVAILABLE)) {
log.error("Server is unavailable");
return Flux.error(new ServerIsUnavailable(
"Failed to fetch geocoding data. Please try again later"));
}
return clientResponse.bodyToFlux(LocationRequest.class);
})
.next()
.timeout(timeout)
.block();
} catch (Exception e) {
log.error("An error occurred while fetching geocoding data: {}", e.getMessage());
throw new LocationClientException("An error occurred while fetching geocoding data", e);
}
}
}
2.Service który zapisuje współrzędne w bazie danych
@Service
@Slf4j
public class LocationServiceImpl implements LocationService {
private final LocationDAO locationDAO;
private final LocationApiClient locationApiClient;
@Autowired
public LocationServiceImpl(LocationDAO locationDAO, LocationApiClient locationApiClient) {
this.locationDAO = locationDAO;
this.locationApiClient = locationApiClient;
}
@Override
public LocationRequest fetchAndSaveCoordinates(String locationName) {
try {
LocationRequest locationRequest = locationApiClient.fetchGeocodingData(locationName);
validateLocationRequest(locationRequest);
saveLocationIfNotExist(locationName, locationRequest);
return locationRequest;
} catch (LocationNotFound exception) {
throw exception;
} catch (Exception ex) {
log.error("An unexpected error occurred", ex);
throw new LocationServiceException("An unexpected error occurred", ex);
}
}
private void validateLocationRequest(LocationRequest locationRequest) {
if (locationRequest == null) {
throw new LocationNotFound("The specified location could not be found in our data source.");
}
}
private void saveLocationIfNotExist(String locationName, LocationRequest locationRequest) {
Location existingLocation = locationDAO.findLocationByLocationName(locationName);
if (existingLocation == null) {
saveLocation(locationRequest);
}
}
private void saveLocation(LocationRequest locationRequest) {
Location location = mapToLocationEntity(locationRequest);
locationDAO.save(location);
log.info("Successfully saved the location {}", location.getLocationName());
}
private Location mapToLocationEntity(LocationRequest locationRequest) {
Location location = new Location();
location.setLocationName(locationRequest.locationName());
location.setLatitude(locationRequest.latitude());
location.setLongitude(locationRequest.longitude());
location.setState(locationRequest.state());
location.setCountry(locationRequest.country());
return location;
}
}
3.Controller
@RestController
@RequestMapping("/api/location/coordinates/")
public class LocationController {
private LocationService locationService;
@Autowired
public LocationController(LocationService locationService) {
this.locationService = locationService;
}
@GetMapping
public void handleErrorWhenLocationIsNotGiven() {
throw new LocationNotGiven("Location name cannot be null or empty. First you need to specify your location.");
}
@GetMapping("{locationName}")
public LocationRequest fetchLocationCoordinates(
@PathVariable String locationName) throws IOException {
return locationService.fetchAndSaveCoordinates(locationName);
}
}
Chciałem rzucić wyjątek w chwili, gdy użytkownik nie wprowadzi żadnych danych, a będzie chciał wyszukać współrzędne.
W tym celu stworzyłem w controllerze mapowanie
@GetMapping
public void handleErrorWhenLocationIsNotGiven() {
throw new LocationNotGiven("Location name cannot be null or empty. First you need to specify your location.");
}
Czy w pozostałych warstwach(service i apiClient), również powinienem sprawdzać i testować kod na wypadek, gdyby wejście użytkownika było puste ?
Mi się wydaje, że nie, bo w sytuacji, kiedy użytkownik będzie próbował wyszukać współrzędne nie wprowadzając nic, controller przekieruje go na mapowanie GetMapping i rzuci wyjątek. Ale dopiero się uczę i wolę zapytać kogoś bardziej doświadczonego.
Z góry dzięki za pomoc.