Skip to content

Instantly share code, notes, and snippets.

@karaggeorge
Created June 2, 2020 19:04
Show Gist options
  • Save karaggeorge/616dba9e7c95ea186ee260045d06c8a3 to your computer and use it in GitHub Desktop.
Save karaggeorge/616dba9e7c95ea186ee260045d06c8a3 to your computer and use it in GitHub Desktop.
  • Get the .proto file from the API team
  • Find you feature's data module (i.e. storemode-data)
  • For the next few steps, I suggest using the Project view instead of Android for the file menu
  • Add the following to your module's build.gradle, after the other apply statements at the top of the file:

apply from: '../build-protobuf.gradle'

  • If your proto file includes other types like Errors, you'll also need to include the following in your dependencies:

/**

  • Common proto files */ implementation project(':adp-ds-core-data')
  • Check if the folder src/main/proto exists under your module, and if it doesn't create it

i.e. storemode-data/src/main/proto

  • Place the proto file/files in that directory and rebuild the project
  • After it completes successfully, you can find the generated data classes under build/generated/source/proto/debug/javalite

i.e. storemode-data/build/generated/source/proto/debug/javalite/{your api name}

  • Those classes are going to replace the api return values
  • Located the Api file that contains the endpoint you are replacing. If needed, update the path/headers
  • You will definitely have to add the @ProtobufApi decorator above the rest and remove the application/json header if it exists
  • If you don't know the right headers, ask the backend team for guidance
  • Change the return value to use the appropriate class from the generated ones above instead of the ones it's using now

// **** The following steps are for if the api was already using xApi **** //

  • If the endpoint was already using xApi, most likely, the return value will be an xApi data class, and there's a .toDomain method declared in a file and used in the RepoImpl to convert it to the domain class.
  • If that is the case, you can remove that xApi class (if this is the only place it's used) and replace it with the generated one from the proto file.
  • You will also need to replace the toDomain method with one that is implemented on the generated class
  • The names repeat a lot so you might have to make sure you have the right classes. It might look something like:

import com.macys.mobileapp.xapi.wallet.WalletSummary

internal fun WalletSummary.toDomain(): wallet.domain.WalletSummary { return wallet.domain.WalletSummary( macysPay = macysPay.toDomain(), starMoneyRewardsCount = noOfStarMoneyRewards, macysMoneyCount = noOfMacysMoney, savedOfferCount = noOfSavedOffers, creditCardCount = noOfCreditCards, notification = notification.toDomain() ) }

Here, the WalletSummary imported is the generated class, and the return type also called WalletSummary is the domain class

  • Finally make sure the repo implementation class is using the right types/toDomain methods

// **** The following steps are for if the api was NOT using xApi **** //

  • If your api did not already use xApi, you'll have to create a file for those toDomain mappings, create them and then update the repo implementation class to call those on the api result before returning it.
  • The contents of the mapper file will looks something like this:

import com.macys.mobileapp.xapi.wallet.WalletSummary

internal fun WalletSummary.toDomain(): wallet.domain.WalletSummary { return wallet.domain.WalletSummary( macysPay = macysPay.toDomain(), starMoneyRewardsCount = noOfStarMoneyRewards, macysMoneyCount = noOfMacysMoney, savedOfferCount = noOfSavedOffers, creditCardCount = noOfCreditCards, notification = notification.toDomain() ) }

Here, the WalletSummary imported is the generated class, and the return type also called WalletSummary is the domain class

  • After the mapping is done, you'll have to use it in the repo implementation to convert the api result to the domain. That will look something like this:

return api.getQPUOrdersResponse() .map { response -> response.orders.orderList.map { it.toDomain() } <-- this is where the conversion happens } .map { Result.withValue(it) } .onErrorReturn { Result.OnError(NetworkError()) }

The above will vary and depend on the endpoint/implementation but the toDomain will need to be placed somewhere in that method

  • For all the above, keep in mind that if there's complex types with nested classes you might have to implement multiple .toDomain methods for those

If you are looking for examples, the wallet-data and purchase-history-data modules have a bunch of endpoints/models

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment