Introdução ao Retrofit

Introdução ao Retrofit

1. Visão geral

Retrofit é um cliente HTTP de tipo seguro para Android e Java - desenvolvido pela Square (Dagger,Okhttp).

Neste artigo, vamos explicar como usar o Retrofit, com foco em seus recursos mais interessantes. Mais notavelmente, discutiremos a API síncrona e assíncrona, como usá-la com autenticação, registro e algumas boas práticas de modelagem.

2. Configurando o exemplo

Começaremos adicionando a biblioteca Retrofit e o conversor Gson:


    com.squareup.retrofit2
    retrofit
    2.3.0


    com.squareup.retrofit2
    converter-gson
    2.3.0

Para as versões mais recentes, dê uma olhada emRetrofiteconverter-gson no repositório Maven Central.

3. Modelagem API

A atualização modela os pontos de extremidade REST como interfaces Java, tornando-os muito simples de entender e consumir.

Vamos modelar ouser API do GitHub; tem um endpointGET que retorna isso no formato JSON:

{
  login: "mojombo",
  id: 1,
  url: "https://api.github.com/users/mojombo",
  ...
}

A atualização funciona modelando sobre uma URL base e fazendo com que as interfaces retornem as entidades do terminal REST.

Para fins de simplicidade, vamos pegar uma pequena parte do JSON modelando nossa classeUser que vai pegar os valores quando os recebermos:

public class User {
    private String login;
    private long id;
    private String url;
    // ...

    // standard getters an setters

}

Podemos ver que estamos pegando apenas um subconjunto de propriedades para este exemplo. Retrofit won’t complain about missing properties – since it only maps what we need, nem reclamará se adicionarmos propriedades que não estão no JSON.

Agora podemos passar para a modelagem de interface e explicar algumas das anotações de Retrofit:

public interface UserService {

    @GET("/users")
    public Call> getUsers(
      @Query("per_page") int per_page,
      @Query("page") int page);

    @GET("/users/{username}")
    public Call getUser(@Path("username") String username);
}

Os metadados fornecidos com as anotações são suficientes para a ferramenta gerar implementações de trabalho.

A anotação@GET informa ao cliente qual método HTTP usar e em qual recurso, por exemplo, fornecendo um URL base de “https://api.github.com” ele enviará a solicitação para “https: //api.github.com/users ”.

O “/” inicial em nosso URL relativotells Retrofit that it is an absolute path on the host.

Outra coisa a notar é que usamos parâmetros@Query completamente opcionais, que podem ser passados ​​como nulos se não precisarmos deles, a ferramenta cuidará de ignorar esses parâmetros se eles não tiverem valores.

E por último, mas não menos importante,@Path permite especificar um parâmetro de caminho que será colocado em vez da marcação que usamos no caminho.

4. Synchronous/Asynchronous API

Para construir uma chamada de solicitação HTTP, precisamos primeiro criar nosso objeto Retrofit:

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("https://api.github.com/")
  .addConverterFactory(GsonConverterFactory.create())
  .client(httpClient.build())
  .build();

O Retrofit fornece um construtor conveniente para construir nosso objeto necessário. It needs the base URL which is going to be used for every service call and a converter factory - que cuida da análise dos dados que enviamos e também das respostas que recebemos.

Neste exemplo, vamos usarGsonConverterFactory, que vai mapear nossos dados JSON para a classeUser que definimos anteriormente.

É importante observar que diferentes fábricas atendem a propósitos diferentes, então tenha em mente que também podemos usar fábricas para XML, proto-buffers ou até mesmo criar uma para um protocolo personalizado. Para uma lista de fábricas já implementadas, podemos dar uma olhada emhere.

A última dependência éOKHttpClient - que é um cliente HTTP e HTTP / 2 para aplicativos Android e Java. Isso vai cuidar da conexão com o servidor e do envio e recuperação de informações. Também podemos adicionar cabeçalhos e interceptores para cada chamada, que veremos em nossa seção de autenticação.

Agora que temos nosso objeto Retrofit, podemos construir nossa chamada de serviço, vamos dar uma olhada em como fazer isso de maneira síncrona:

UserService service = retrofit.create(UserService.class);
Call callSync = service.getUser("eugenp");

try {
    Response response = callSync.execute();
    User user = response.body();
} catch (Exception ex) { ... }

Aqui, podemos ver como o Retrofit cuida da construção de nossa interface de serviço injetando o código necessário para fazer a solicitação, com base em nossas anotações anteriores.

Depois disso, obtemos um objetoCall<User> que é usado para executar a solicitação à API do GitHub. The most important method here is execute, que é usado para executar uma chamada de forma síncrona e irá bloquear a thread atual enquanto transfere os dados.

Depois que a chamada é executada com sucesso, podemos recuperar o corpo da resposta - já em um objeto do usuário - graças ao nossoGsonConverterFactory.

Fazer uma chamada síncrona é muito fácil, mas geralmente usamos uma solicitação assíncrona sem bloqueio:

UserService service = retrofit.create(UserService.class);
Call callAsync = service.getUser("eugenp");

callAsync.enqueue(new Callback() {
    @Override
    public void onResponse(Call call, Response response) {
        User user = response.body();
    }

    @Override
    public void onFailure(Call call, Throwable throwable) {
        System.out.println(throwable);
    }
});

Agora, em vez do método execute, usamos o métodoenqueue - que usa uma sinterfaceCallback<User>como parâmetro para lidar com o sucesso ou a falha da solicitação. Observe que isso será executado em um thread separado.

Depois que a chamada foi concluída com êxito, podemos recuperar o corpo da mesma maneira que fizemos anteriormente.

5. Fazendo uma classeServiceGenerator reutilizável

Agora que vimos como construir nosso objeto Retrofit e como consumir uma API, podemos ver que não queremos escrever o construtor indefinidamente.

O que queremos é uma classe reutilizável que nos permita criar esse objeto uma vez e reutilizá-lo durante toda a vida útil de nosso aplicativo:

public class GitHubServiceGenerator {

    private static final String BASE_URL = "https://api.github.com/";

    private static Retrofit.Builder builder
      = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create());

    private static Retrofit retrofit = builder.build();

    private static OkHttpClient.Builder httpClient
      = new OkHttpClient.Builder();

    public static  S createService(Class serviceClass) {
        return retrofit.create(serviceClass);
    }
}

Toda a lógica de criação do objeto Retrofit agora é movida para esta classeGitHubServiceGenerator, o que a torna uma classe de cliente sustentável que impede a repetição do código.

Aqui está um exemplo simples de como usá-lo:

UserService service
  = GitHubServiceGenerator.createService(UserService.class);

Agora, se nós, por exemplo, criássemos umRepositoryService,, poderíamos reutilizar essa classe e simplificar a criação.

In the next section, vamos estendê-lo e adicionar recursos de autenticação.

6. Autenticação

A maioria das APIs possui alguma autenticação para garantir o acesso a ela.

Levando em consideração nossa classe de gerador anterior, vamos adicionar um método de criação de serviço, que leva um token JWT com o cabeçalhoAuthorization:

public static  S createService(Class serviceClass, final String token ) {
   if ( token != null ) {
       httpClient.interceptors().clear();
       httpClient.addInterceptor( chain -> {
           Request original = chain.request();
           Request request = original.newBuilder()
             .header("Authorization", token)
             .build();
           return chain.proceed(request);
       });
       builder.client(httpClient.build());
       retrofit = builder.build();
   }
   return retrofit.create(serviceClass);
}

Para adicionar um cabeçalho à nossa solicitação, precisamos usar os recursos de interceptor deOkHttp; fazemos isso usando nosso construtor previamente definido e reconstruindo o objeto Retrofit.

Observe que este é um exemplo simples de autenticação, mas com o uso de interceptores, podemos usar qualquer autenticação como OAuth, usuário / senha etc.

7. Exploração madeireira

Nesta seção, vamos estender ainda mais nossoGitHubServiceGenerator para recursos de registro, que são muito importantes para fins de depuração em cada projeto.

Vamos usar nosso conhecimento anterior sobre interceptores, mas precisamos de uma dependência adicional, que éHttpLoggingInterceptor de OkHttp, vamos adicioná-lo ao nossopom.xml:


    com.squareup.okhttp3
    logging-interceptor
    3.9.0

Agora vamos estender nossa classeGitHubServiceGenerator:

public class GitHubServiceGenerator {

    private static final String BASE_URL = "https://api.github.com/";

    private static Retrofit.Builder builder
      = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create());

    private static Retrofit retrofit = builder.build();

    private static OkHttpClient.Builder httpClient
      = new OkHttpClient.Builder();

    private static HttpLoggingInterceptor logging
      = new HttpLoggingInterceptor()
        .setLevel(HttpLoggingInterceptor.Level.BASIC);

    public static  S createService(Class serviceClass) {
        if (!httpClient.interceptors().contains(logging)) {
            httpClient.addInterceptor(logging);
            builder.client(httpClient.build());
            retrofit = builder.build();
        }
        return retrofit.create(serviceClass);
    }

    public static  S createService(Class serviceClass, final String token) {
        if (token != null) {
            httpClient.interceptors().clear();
            httpClient.addInterceptor( chain -> {
                Request original = chain.request();
                Request.Builder builder1 = original.newBuilder()
                  .header("Authorization", token);
                Request request = builder1.build();
                return chain.proceed(request);
            });
            builder.client(httpClient.build());
            retrofit = builder.build();
        }
        return retrofit.create(serviceClass);
    }
}

Esta é a forma final de nossa classe, podemos ver como adicionamos oHttpLoggingInterceptor, e o configuramos para log básico, que irá registrar o tempo que levou para fazer a solicitação, o endpoint, o status de cada pedido, etc.

É importante dar uma olhada em como verificamos se o interceptor existe, para que não o adicionemos acidentalmente duas vezes.

8. Conclusão

Neste guia abrangente, vimos a excelente biblioteca Retrofit, concentrando-se em sua API Sync / Async, algumas práticas recomendadas de modelagem, autenticação e log.

A biblioteca pode ser usada de maneiras muito complexas e úteis; para um caso de uso avançado com RxJava, dê uma olhada emthis tutorial.

E, como sempre, o código-fonte pode ser encontradoover on GitHub.