Home > Blockchain >  How to perform a request chains in clean architecture?
How to perform a request chains in clean architecture?

Time:09-29

In our case, I need to perform request chain on application startup, for examples

  1. Application needs retrieve location by gis or IP address
  2. request a server list by location via http
  3. request remote configs from a server which in server list we got

I create a data layer for each item

class DefaultLocationRepository(
  @LocateByGis gisLocationDataSource: LocationDataSource,
  @LocateByIp ipLocationDataSource: LocationDataSource
): LocationRepository {
   suspend fun locate(): Result<Location> {
      ....
   }
}

class DefaultServerRepository(
  remoteServerDataSource: RemoteServerDataSource
): ServerRepository {
  suspend fun retrieve(location: Location): List<Server> {
  }
}


class DefaultRemoteConfigRepository (
  remoteConfigDataSource: RemoteConfigDataSource
): RemoteConfigDataSource {
  suspend fun retrieve(server: List<Server>) {
  }
}


My question is, what are the best practices for chain these tasks? I can make a use case for each action

class LocateUseCase
class RetrieveServersUseCase
class RetrieveRemoteConfigUseCase


class MainViewModel: ViewModel() {
  
   suspend fun start() {
     locateUserCase().onSuccess { 
       retrieveServerUseCase(GetLocationUseCase()).onSuccess {
         retrieveConfigServerUseCase(GetServerListUseCase()).onSuccess {
            // balabala...
         }
       }
     }
   }
}

I think It's too ugly

and I can do it by hilt injection, the repository returns a Flow instead of a suspend function call,


class LocatonRepository() {
   private var latestLocation: Location? = null
  
   val location: Flow<Location> {
     if (latestLocation != null) {
       emit (latestLocation!!)
       return@flow
     }

     dataSource.get().onSuccess { emit(it) }
   }
}

// Modules

@InstallIn(Singleton::class::java)
@Module 
class Modules {
  
  @Provides
  fun provideLocation(repository: LocationRepository): Flow<Location> = 
     repository.location

}


when Flow inject into ServerList, server repository can trigger locate location requet by location.first()

but how to implement cancel/retry logic in flow chain? Or let ui known which step is wrong or stucked?

CodePudding user response:

what about this:

suspend fun start() {
 val locationResult = locateUserCase()
 if(locationResult.isFailure()) {
    // do location error handling
    return
 } 
 val location = locationResult.getOrThrow()
 val serverResult = retrieveServerUseCase(location)
 if(serverResult.isFailure()) {
    // do server error handling
    return
 } 
 val server = serverResult.getOrThrow()
 val configResult = retrieveConfigServerUseCase(server)
 if(configResult.isFailure()) {
    // do config error handling
    return
 }
 
 // do total success handling 
}

You allow each of your cases to return a result, handle the error handling separately and return early to stop continuation. Shows a clear flow between areas, but isn't callback hell.

  • Related