Home > Mobile >  Multiple Retrofit requests dependent on each other in RxJava
Multiple Retrofit requests dependent on each other in RxJava

Time:10-06

I have three API calls in which two are dependent on each other.

I have setted the following endpoints:

interface WeatherApi {

    @GET("/data/2.5/onecall")
    fun getWeather(
        @Query("lat") lat: Double,
        @Query("lon") lon: Double,
        @Query("exclude") exclude: String,
        @Query("units") units: String,
        @Query("appid") appKey: String
    ): Observable<WeatherModel>

    @GET("/geo/1.0/direct")
    fun getCoordinates(
        @Query("q") cityName: String,
        @Query("appid") appKey: String
    ): Observable<LocationModel>

    @GET("geo/1.0/reverse")
    fun getNameForLocation(
        @Query("lat") lat: Double,
        @Query("lon") lon: Double,
        @Query("appid") appKey: String
    ): Observable<LocationModel>

}

and

interface PlacesApi {

    @GET("/maps/api/place/findplacefromtext/json")
    fun getPlaceId(
        @Query("input") cityName: String,
        @Query("inputtype") inputType: String,
        @Query("fields") fields: String,
        @Query("key") appKey: String
    ): Observable<PlacesModel>

}

My repository looks as follows:

class WeatherRepository constructor(
    private val weatherService: WeatherApi,
    private val placesService: PlacesApi,
) {

    fun getCoordinates(cityName: String, appKey: String) =
        weatherService.getCoordinates(cityName, appKey)

    fun getWeather(lat: Double, lon: Double, exclude: String, units: String, appKey: String) =
        weatherService.getWeather(lat, lon, exclude, units, appKey)

    fun getPlaceId(placeName: String, appKey:String) =
        placesService.getPlaceId(placeName, "textquery", "photos", appKey)

}

Right now in ViewModel I would like to fetch all needed data (three models). So I should have some method, in which I will be doing all three requests one after another, as follows:

locationModel = weatherRepository.getCoordinates(city, BuildConfig.WEATHER_API_KEY)
weatherModel = weatherRepository.getWeather(locationModel[0].lat!!, locationModel[0].lon!!)
placesModel = weatherRepository.getPlaceId(weatherModel, BuildConfig.PLACES_API_KEY)

and after all that I need to create new model, which includes all fetched data. Something like:

val cityModel = CityModel(
    locationModel,
    weatherModel,
    placesModel
)

Does anybody know how to do something like this using RxJava in Kotlin?

CodePudding user response:

I'm sure there are multiple ways to do this. The one that comes to mind is not super elegant. You can use flatMap, but you will need to keep track of your models along the way so you can build the last model. You can try using Pair.

Here's the whole idea:

 weatherRepository.getCoordinates(city, BuildConfig.WEATHER_API_KEY)
     .flatMap { locationModel ->
       weatherRepository.getWeather(locationModel[0].lat!!, locationModel[0].lon!!)
         .map { locationModel to it }
     }
     .flatMap { (locationModel, weatherModel) ->
        weatherRepository.getPlaceId(weatherModel, BuildConfig.PLACES_API_KEY)
          .map {
            CityModel(
              locationModel,
              weatherModel,
              it
            )
          }
     }

So first you getCoordinates and use the result to get the weather. Using to you create a Pair that gets "piped" into the next flatMap.

Once inside the last flatMap you destructure the pair into locationModel and weatherModel and use them to fetch the place id.

With everything now you can simply build your CityModel.

CodePudding user response:

You can try the share() operator. Something like below:

locationModelObservable = weatherRepository.getCoordinates(city, BuildConfig.WEATHER_API_KEY).share()
weatherModelObservable = locationModel.flatMap { weatherRepository.getWeather(it[0].lat!!, it[0].lon!!) }.share()
placesModelObservable = weatherModel.flatMap { weatherRepository.getPlaceId(it, BuildConfig.PLACES_API_KEY) }

zip(locationModelObservable, weatherModelObservable, placesModelObservable) { .. }
  • Related