1. Información general
Retrofit es un cliente HTTP con seguridad de tipos para Android y Java, desarrollado por Square (Dagger, Okhttp).
En este artículo, vamos a explicar cómo utilizar Retrofit, centrándonos en sus características más interesantes. Más notablemente, discutiremos la API síncrona y asincrónica, cómo usarla con autenticación, registro y algunas buenas prácticas de modelado.
2. Configurar el ejemplo
Comenzaremos agregando la biblioteca Retrofit y el convertidor Gson:
com.squareup.retrofit2 retrofit 2.3.0 com.squareup.retrofit2 converter-gson 2.3.0
Para conocer las últimas versiones, eche un vistazo a Retrofit y converter-gson en el repositorio de Maven Central.
3. Modelado de API
Adapte modelos de puntos finales REST como interfaces Java, haciéndolos muy fáciles de entender y consumir.
Modelaremos la API de usuario de GitHub; esto tiene un punto final GET que devuelve esto en formato JSON:
{ login: "mojombo", id: 1, url: "//api.github.com/users/mojombo", ... }
La modificación funciona modelando sobre una URL base y haciendo que las interfaces devuelvan las entidades desde el punto final REST.
Por motivos de simplicidad, vamos a tomar una pequeña parte del JSON modelando nuestra clase User que tomará los valores cuando los hayamos recibido:
public class User { private String login; private long id; private String url; // ... // standard getters an setters }
Podemos ver que solo estamos tomando un subconjunto de propiedades para este ejemplo. Retrofit no se quejará de las propiedades faltantes, ya que solo asigna lo que necesitamos , ni siquiera se quejará si agregamos propiedades que no están en JSON.
Ahora podemos pasar al modelado de la interfaz y explicar algunas de las anotaciones 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); }
Los metadatos provistos con anotaciones son suficientes para que la herramienta genere implementaciones de trabajo.
La anotación @GET le dice al cliente qué método HTTP usar y en qué recurso, por ejemplo, al proporcionar una URL base de “//api.github.com”, enviará la solicitud a “//api.github.com / usuarios ”.
La "/" inicial en nuestra URL relativa le dice a Retrofit que es una ruta absoluta en el host.
Otra cosa a tener en cuenta es que usamos parámetros @Query completamente opcionales , los cuales se pueden pasar como nulos si no los necesitamos, la herramienta se encargará de ignorar estos parámetros si no tienen valores.
Y por último, pero no menos importante, @Path nos permite especificar un parámetro de ruta que se colocará en lugar del marcado que usamos en la ruta.
4. API síncrona / asíncrona
Para construir una llamada de solicitud HTTP, primero necesitamos construir nuestro objeto Retrofit:
OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("//api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .client(httpClient.build()) .build();
Retrofit proporciona un constructor conveniente para construir nuestro objeto requerido. Necesita la URL base que se utilizará para cada llamada de servicio y una fábrica de convertidores , que se encarga del análisis de los datos que enviamos y también de las respuestas que recibimos.
En este ejemplo, usaremos GsonConverterFactory , que mapeará nuestros datos JSON a la clase de usuario que definimos anteriormente.
Es importante tener en cuenta que las diferentes fábricas tienen diferentes propósitos, así que tenga en cuenta que también podemos usar fábricas para XML, proto-búfer o incluso crear una para un protocolo personalizado. Para obtener una lista de fábricas ya implementadas, podemos echar un vistazo aquí.
La última dependencia es OKHttpClient , que es un cliente HTTP y HTTP / 2 para aplicaciones de Android y Java. Esto se ocupará de conectarse al servidor y del envío y recuperación de información. También podríamos agregar encabezados e interceptores para cada llamada, lo cual veremos en nuestra sección de autenticación.
Ahora que tenemos nuestro objeto Retrofit, podemos construir nuestra llamada de servicio, echemos un vistazo a cómo hacerlo de forma 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) { ... }
Aquí, podemos ver cómo Retrofit se encarga de la construcción de nuestra interfaz de servicio inyectando el código necesario para realizar la solicitud, en base a nuestras anotaciones anteriores.
Después de eso, obtenemos un objeto Call que es el que se usa para ejecutar la solicitud a la API de GitHub. El método más importante aquí es ejecutar , que se utiliza para ejecutar una llamada de forma sincrónica y bloqueará el hilo actual mientras se transfieren los datos.
Una vez que la llamada se ejecuta correctamente, podemos recuperar el cuerpo de la respuesta, ya en un objeto de usuario, gracias a nuestro GsonConverterFactory .
Hacer una llamada sincrónica es muy fácil, pero usualmente usamos una solicitud asincrónica sin bloqueo:
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); } });
Ahora, en lugar del método de ejecución, usamos el método de puesta en cola , que toma una interfaz de devolución de llamada como parámetro para manejar el éxito o el fracaso de la solicitud. Tenga en cuenta que esto se ejecutará en un hilo separado.
Una vez que la llamada finalizó correctamente, podemos recuperar el cuerpo de la misma manera que lo hicimos anteriormente.
5. Hacer una clase ServiceGenerator reutilizable
Ahora que vimos cómo construir nuestro objeto Retrofit y cómo consumir una API, podemos ver que no queremos seguir escribiendo el constructor una y otra vez.
Lo que queremos es una clase reutilizable que nos permita crear este objeto una vez y reutilizarlo durante la vida útil de nuestra aplicación:
public class GitHubServiceGenerator { private static final String BASE_URL = "//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); } }
All the logic of creating the Retrofit object is now moved to this GitHubServiceGenerator class, this makes it a sustainable client class which stops the code from repeating.
Here's a simple example of how to use it :
UserService service = GitHubServiceGenerator.createService(UserService.class);
Now if we, for example, were to create a RepositoryService, we could reuse this class and simplify the creation.
In the next section, we're going to extend it and add authentication capabilities.
6. Authentication
Most APIs have some authentication to secure access to it.
Taking into account our previous generator class, we're going to add a create service method, that takes a JWT token with the Authorization header :
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); }
To add a header to our request, we need to use the interceptor capabilities of OkHttp; we do this by using our previously define builder and by reconstructing the Retrofit object.
Note that this a simple auth example, but with the use of interceptors we can use any authentication such as OAuth, user/password, etc.
7. Logging
In this section, we're going to further extend our GitHubServiceGenerator for logging capabilities, which are very important for debugging purposes in every project.
We're going to use our previous knowledge of interceptors, but we need an additional dependency, which is the HttpLoggingInterceptor from OkHttp, let us add it to our pom.xml:
com.squareup.okhttp3 logging-interceptor 3.9.0
Ahora extendamos nuestra clase GitHubServiceGenerator :
public class GitHubServiceGenerator { private static final String BASE_URL = "//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 es la forma final de nuestra clase, podemos ver cómo agregamos el HttpLoggingInterceptor y lo configuramos para el registro básico, que registrará el tiempo que tomó realizar la solicitud, el punto final, el estado de cada solicitud, etc.
Es importante echar un vistazo a cómo comprobamos si existe el interceptor, para que no lo agreguemos accidentalmente dos veces.
8. Conclusión
En esta guía extensa, echamos un vistazo a la excelente biblioteca Retrofit centrándonos en su API Sync / Async, algunas de las mejores prácticas de modelado, autenticación y registro.
La biblioteca se puede utilizar de formas muy complejas y útiles; para un caso de uso avanzado con RxJava, consulte este tutorial.
Y, como siempre, el código fuente se puede encontrar en GitHub.