Chamadas de API do GCP de Retrofit2 assíncrono com Anko e Kotlin

Tempo de leitura: 4 minutes

No desenvolvimento do Android, as chamadas de API REST são cidadãos de primeira classe, o que faz os desenvolvedores procurarem melhores maneiras, linguagens, estruturas e bibliotecas para o aumento geral de produtividade, escalabilidade e simplicidade.

Este artigo descreve como:
– Autenticar e autorizar ao usar APIs do Google Cloud Platform
– Configurar interface de chamadas Retrofit2 com parâmetros e cabeçalhos dinâmicos
– Faça uma chamada de API em um exemplo de API GCP BigQuery
Bibliotecas usadas: Retrofit 2, Google API client, Anko

Tradicionalmente, adicione as próximas dependências para o Google API client, Retrofit 2 e Anko às dependências do módulo build.gradle:

// Atualize com a versão real das bibliotecas
implementation "org.jetbrains.anko:anko:$version"
implementation "com.squareup.retrofit2:retrofit:$version"
implementation "com.squareup.retrofit2:converter-gson:$version"
implementation "com.google.api-client:google-api-client:$version"

 

Autenticação e autorização do GCP

IAM GCP Service
IAM GCP Service

Cada uma das APIs REST do GCP requer autenticação e autorização. Quanto ao estágio de desenvolvimento local, é recomendado o uso de contas de serviço de acordo com a descrição das APIs do Google Cloud Platform:

 

Importante: para quase todos os casos, se você estiver desenvolvendo localmente ou em um aplicativo de produção, você deve usar contas de serviço, em vez de contas de usuário ou chaves de API.”

// Access scopes
private val accessScope = listOf("https://www.googleapis.com/auth/cloud-platform.read-only")
private var token = "Empty"

// Receber token Google OAuth 2 para acesso à API
private fun authenticateAndAuthorize() {
    doAsync {
        val googleCredential = GoogleCredential
            .fromStream(ctx.assets.open("service-account.json"))
            .createScoped(accessScope)
        googleCredential.refreshToken()
        [email protected] = googleCredential.accessToken
    }
}

Em primeiro lugar, os escopos de acesso para a API do GCP são definidos, dependendo do serviço que pode exigir um ou mais, mas no exemplo atual, obteremos os dados da tabela do GCP BigQuery, o que requer um escopo somente leitura.

A função authenticateAndAuthorize() abre um fluxo para leitura do arquivo service-account.json localizado nos ativos do aplicativo que é a chave da conta de serviço e contém informações de direitos de acesso.

Observação: a conta de serviço deve ter scopes de acesso descritos anteriormente para executar ações.

O doAsync {<actions>} da Anko é uma maneira simples de realizar tarefas em segundo plano em outro thread. O artigo de Leiva Antonio´s sobre os usos do Anko para tarefas em segundo plano é uma fonte perfeita para começar.

Como resultado, um token de acesso é recebido e será usado para um cabeçalho dinâmico na chamada de Retrofit para a API do BigQuery.

 

Configuração de retrofit2

Retrofit2Retrofit2 é uma biblioteca HTTP bem conhecida e popular e nem todos os desenvolvedores a usam, mas com certeza já ouviram falar sobre ela. Existem outras alternativas (como khttp para testes simples), mas a indústria exige que você esteja no auge e mude suas preferências em tempo hábil.

“Retrofit é um cliente HTTP de tipo seguro para Android e Java”

Mas não são apenas esses recursos que tornam o Retrofit tão popular. Neste exemplo, a chamada para apenas uma instância é mostrada. Em vez disso, na produção, você atenderá chamadas de API para diferentes instâncias do serviço e manterá referências de URL como variáveis de string ou especificará cabeçalhos, corpo ou parâmetros diferentes o tempo todo, não é uma escolha sábia.

// Interface de retrofit
interface GCPService {
    @GET("/bigquery/v2/projects/weather-231121/datasets/WeatherDataSet/tables/WeatherDataTable/data")
    fun getTable(@Header("Authorization") token: String, @Query("startIndex") startIndex: Int): Call<JsonObject>
}

// Construtor de retrofit
private val retrofitBuilder = Retrofit.Builder()
    .baseUrl("https://content.googleapis.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

// Criar serviço
private val gcpService = retrofitBuilder.create(BigQueryAPI.GCPService::class.java)

A interface GCPService é um esqueleto para recursos de Retrofit. Aqui, as anotações @GET, @POST, @PUT, @DELETE e @HEAD estão descrevendo o tipo de uma solicitação HTTP correspondente. Além disso, o caminho relativo da URL é especificado e posteriormente concatenado com baseUrl para formar uma URL de solicitação. Isso permite o uso simples de diferentes APIs do mesmo serviço e depende de você como diferenciar solicitações: crie diferentes funções e caminhos relativos para eles ou especifique a anotação @Path como um parâmetro de função e use-a em um caminho relativo.

Os parâmetros getTable() manipulam anotações como @Header, @Query, @Body, @Path etc. e são usados para valores dinâmicos.

Observação: todos os cabeçalhos dinâmicos da solicitação devem ser passados como parâmetros de função.

retrofitBuilder define:
– URL base
– fábrica de conversor (aqui o BigQuery retorna JsonObject em resposta e GsonConverterFactory é usado, mas você pode usar seu próprio conversor).
– As solicitações de retrofit são baseadas em OkHttp e isso permite adicionar interceptores de registro que são ignorados para simplificar.

Finalmente, um gcpService: class é criado.

 

Chamada da API BigQuery

Serviço BigQuery GCP
Serviço BigQuery GCP

BigQuery é um serviço do Google Cloud Platform e no exemplo atual é usado para manter os dados que são enviados da plataforma Android Things do projeto IoT original relacionado a este exemplo.

Como resultado da chamada da API, os dados da tabela são recebidos e passados para o aplicativo gráfico em tempo real.

“O BigQuery é um data warehouse em nuvem sem servidor, altamente escalonável e econômico com um mecanismo de BI em memória e aprendizado de máquina integrado.”

Abaixo, a função pullData() é apresentada, a qual verifica o token de autorização e autenticação, chama a função authenticateAndAuthorize() se necessário e faz uma chamada de API assíncrona:

// Get table
fun pullData() {
    when (token) {
        "Empty" -> {
            authenticateAndAuthorize()
        }
        else -> {
            doAsync {
                val apiCall = gcpService.getTable("Bearer $token", 15).execute()
                Log.d("JSON", apiCall.body().toString())
            }
        }
    }
}

O valor apiCall contém o resultado da execução de getTable() descrito na interface GCPService anteriormente. getTable() também recebe dois parâmetros:
– uma string dinâmica que é usada como cabeçalho de “Autorização” (lembre-se de que cabeçalhos dinâmicos podem ser usados apenas como parâmetros de função)
– parâmetro de consulta que é adicionado ao URL de solicitação e especificado como anotação @Query anteriormente.

 

Final String

O retrofit pode realizar chamadas síncronas e assíncronas, mas para mim, descobri que o uso do doAsync da Anko simplifica isso e posso controlar quando a tarefa é realizada em um thread separado ou não. Além disso, Anko e Kotlin, bem como o Android Studio, são escritos por JetBrains e eu sou um grande fã de seu ecossistema e abordagens. Você verá muitos outros usos do Anko, especialmente para construção de IU mais tarde, pois este artigo é uma pequena parte do meu projeto interno de IoT.

Visits: 2 Visits: 1192345