Search code examples
scalafunctional-programming

Convert Future[Object] to another Future[Object] containing a list


I have a method that calls a third-party endpoint to return a list of provider objects of Future type. Now I want to call this method and convert that object to a different future object containing the list. Here are the models:

case class ThirdPartyProvidersResponse(providers: List[ThirdPartyProvider])

case class ThirdPartyProvider(
    id: String,
    config: List[Config]
)

// Convert ThirdPartyProvidersResponse to DomainProvidersResponse

case class DomainProvidersResponse(
    providers: List[DomainProviderResponse]
)

case class DomainProviderResponse(
    code: Option[DomainProviderType],
    enabled: Boolean
)

This is the method signature that I am attempting to implement:

def getProviders(): Future[DomainProvidersResponse]

This is the definition of the API method:

def getProvidersList(): Future[ThirdPartyProvidersResponse]

This is what I have tried:

def getProviders(): Future[DomainProvidersResponse] = {
  var providers: List[DomainProviderResponse] = List()
  thirdPartyServiceHttpClient.getProvidersList().map { response =>
    response.providers.map { providersList =>
      val provider = DomainProviderResponse(
        providerCode = DomainProviderType.findByName(providersList.id),
        enabled = true
      )
      providers :+= provider
    }
  }
  Future.successful(DomainProvidersResponse(providers = providers))
}

The problem with this code is synchronization. I need to wait for the future to execute before the result can be returned. Can we achieve this using flatMap by performing the conversion at once without having to explicitly synchronize?

Any help on this is appreciated. I come from a Java background and am new to Scala.


Solution

  • It seems you need something like map or for-comprehension:

    def getProviders(): Future[DomainProvidersResponse] =
      for {
        response <- thirdPartyServiceHttpClient.getProvidersList()
        domainProviders = response.providers.map { provider =>
         DomainProviderResponse(
            providerCode = DomainProviderType.findByName(providersList.id),
            enabled = true
          )
        }
      } yield DomainProvidersResponse(domainList)
    // or
    def getProviders(): Future[DomainProvidersResponse] =
      thirdPartyServiceHttpClient.getProvidersList().map { response =>
       response.providers.map { provider =>
         DomainProviderResponse(
            providerCode = DomainProviderType.findByName(providersList.id),
            enabled = true
          )
        }
      }.map { domainProviders =>
        DomainProvidersResponse(domainList)
      }