package org.learning.by.example.reactive.microservices.services; import org.learning.by.example.reactive.microservices.exceptions.GetGeoLocationException; import org.learning.by.example.reactive.microservices.exceptions.GeoLocationNotFoundException; import org.learning.by.example.reactive.microservices.exceptions.InvalidParametersException; import org.learning.by.example.reactive.microservices.model.GeographicCoordinates; import org.learning.by.example.reactive.microservices.model.GeoLocationResponse; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; public class GeoLocationServiceImpl implements GeoLocationService { private static final String OK_STATUS = "OK"; private static final String ZERO_RESULTS = "ZERO_RESULTS"; private static final String ERROR_GETTING_LOCATION = "error getting location"; private static final String ERROR_LOCATION_WAS_NULL = "error location was null"; private static final String ADDRESS_NOT_FOUND = "address not found"; private static final String ADDRESS_PARAMETER = "?address="; private static final String MISSING_ADDRESS = "missing address"; WebClient webClient; private final String endPoint; public GeoLocationServiceImpl(final String endPoint) { this.endPoint = endPoint; this.webClient = WebClient.create(); } @Override public Mono<GeographicCoordinates> fromAddress(final Mono<String> addressMono) { return addressMono .transform(this::buildUrl) .transform(this::get) .onErrorResume(throwable -> Mono.error(new GetGeoLocationException(ERROR_GETTING_LOCATION, throwable))) .transform(this::geometryLocation); } Mono<String> buildUrl(final Mono<String> addressMono) { return addressMono.flatMap(address -> { if (address.equals("")) { return Mono.error(new InvalidParametersException(MISSING_ADDRESS)); } return Mono.just(endPoint.concat(ADDRESS_PARAMETER).concat(address)); }); } Mono<GeoLocationResponse> get(final Mono<String> urlMono) { return urlMono.flatMap(url -> webClient .get() .uri(url) .accept(MediaType.APPLICATION_JSON) .exchange() .flatMap(clientResponse -> clientResponse.bodyToMono(GeoLocationResponse.class))); } Mono<GeographicCoordinates> geometryLocation(final Mono<GeoLocationResponse> geoLocationResponseMono) { return geoLocationResponseMono.flatMap(geoLocationResponse -> { if (geoLocationResponse.getStatus() != null) { switch (geoLocationResponse.getStatus()) { case OK_STATUS: return Mono.just( new GeographicCoordinates(geoLocationResponse.getResults()[0].getGeometry().getLocation().getLat(), geoLocationResponse.getResults()[0].getGeometry().getLocation().getLng())); case ZERO_RESULTS: return Mono.error(new GeoLocationNotFoundException(ADDRESS_NOT_FOUND)); default: return Mono.error(new GetGeoLocationException(ERROR_GETTING_LOCATION)); } } else { return Mono.error(new GetGeoLocationException(ERROR_LOCATION_WAS_NULL)); } } ); } }