El escenario

La gran mayoría de aplicaciones actuales necesitan interactuar con alguna API Rest, y para eso hay diversas soluciones.

  • Http request + AsyncTask
  • Volley by Google
  • Retrofit by Square

tIdZkl3

Nosotros nos hemos decidido por Retrofit, ya que destaca tanto por su velocidad, como por su documentación y gran comunidad.

Retrofit?

Retrofit es un cliente REST para Android y Java, desarrollada por Square, muy simple y fácil de aprender.

Permite hacer peticiones GET; POST, PUT, PATCH, DELETE y HEAD , gestionar diferentes tipos de parámetros y parsear automáticamente la respuesta a un POJO.

Primeros pasos

 El primer paso es añadir la dependencia en nuestro proyecto via

MAVEN

  <groupId>com.squareup.retrofit</groupId>
  <artifactId>retrofit</artifactId>
  <version>1.9.0</version>

GRADLE

compile 'com.squareup.retrofit:retrofit:1.9.0'

 

Código

A continuación necessitamos 3 classes para poder usar Retrofit

  • POJO: Representación del Json o XML preveniente de la API REST
  • Interface (Service): Definición de las diferentes llamadas a la API REST
  • RestAdapter: Cliente que usaremos para realizar y configurar nuestras peticiones.

Imaginemos que usando la API de GitHub, queremos obtener un repository, consultando la siguiente URL:

https://api.github.com/repos/{owner}/{name}

Lo que nos da como resultado en JSON:

{
  "id": 2349728,
  "name": "android",
  "full_name": "alorma/gitskarios",
  "owner": {
            ...
           }
   ...
}

Creamos nuestra interface GithubRepositoryService.java

public interface GithubRepositoryService {

    @GET("/repos/{owner}/{name}")
    Repository repositorySync(@Path("owner") String owner, @Path("name") String name);

    @GET("/repos/{owner}/{name}")
    void repositoryAsync(@Path("owner") String owner, @Path("name") String name,   Callback callback);

}

Retrofit permite hacer las peticiones de manera sincrona o asincrona, así como usando RxJava (para uso en Desktop).

Esta configuración se realiza mediante la respuesta del método, o añadiendo el párametro Callback al final de la petición.

Síncrono
public interface GithubRepositoryService {
    @GET("/repos/{owner}/{name}")
    Repository repository(@Path("owner") String owner, @Path("name") String name);
}
Asíncrono
public interface GithubRepositoryService {
    @GET("/repos/{owner}/{name}")
    void repository(@Path("owner") String owner, @Path("name") String name,  Callback<Repository> callback);
}

No se permite usar los dos tipos a la vez

@GET("/repos/{owner}/{name}")
Repository repository(@Path("owner") String owner, @Path("name") String name,  Callback<Repository> callback);

Ejecución

Y a continuación creamos la instancia de RestAdapter y ejecutamos la petición.

public Repository getRepositorySync(String owner, String name) {
     RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.github.com")
    .build();

    GithubRepositoryService service = restAdapter.create(GithubRepositoryService.class);
    
    return service.repository(owner, name);
}

Esté método solo nos provee del objecto Parseado, no podemos acceder a la respuesta HTTP en raw, o los headers.

 

public void getRepositoryAsync(String owner, String name) {
     RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.github.com")
    .build();

    GithubRepositoryService service = restAdapter.create(GithubRepositoryService.class);
 
    Callback callback = new Callback {
        
       @Override 
       public void success(Repository repository, final Response response) { ... }

       @Override 
       public void failure(final RetrofitError error) { ... }
        
    }
   
    service.repository(owner, name, callback);
}

El método succes se ejecutará si todo ha funcionado bien, y nos devuelve el Objecto parseado, y un Response, que contiene la respuesta HTTP en Raw, así como el código HTTP, los headers, etc…

 

Para hacer peticiones POST, PUT, PATCH y DELETE haremos exactamente lo mismo, crear la interface con sus anotaciones @POST, @DELETE… y llamar a RestAdapter.

Configuración

Retrofit, a través de RestAdapter.Builder admite muchos parámetros de configuración.

Converter

XML, Json, Texto plano… con retrofit podemos gestionar el Accept-Type de nuestras APIs, indicandole que tipo de respuesta esperar, y tratarla de la manera adecuada.

@Headers({
    "Accept: application/vnd.github.v3.full+xml"
})
@GET("/repos/{owner}/{name}")
void repositoryAsync(@Path("owner") String owner, @Path("name") String name,   Callback callback);

Retrofit por defecto trabaja con JSON, usando GSON para parsear, pero podemos modificar este comportamiento mediante el método

.setConverter(new SimpleXMLConverter())

https://github.com/square/retrofit/tree/master/retrofit-converters

 

ErrorHandler

Podemos interceptar gestionar los errores que se produzcan en nuestras peticiones de manera única para todas ellas.

.setErrorHandler(new ErrorHandler() {...})
@Override
public Throwable handleError(RetrofitError cause) {
 Response r = cause.getResponse();
 if (r != null && r.getStatus() == 401) {
 return new UnauthorizedException(cause);
 }
 return cause;
} ​​

Esto no bloquea la petición, y igualmente llega al método fail(RetrofitError error) del Callback.

Log

Podemos indicar a Retrofit que muestre por el Log los datos de las peticiones que hagamos, configurando que queremos la información Básica, las cabeceras (Headers) o todo el Log, lo que mostrará toda la información relativa a la petición (headers, body, respuesta, tiempos, …)

.setLogLevel(RestAdapter.LogLevel.BASIC)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setLogLevel(RestAdapter.LogLevel.HEADERS)
.setLogLevel(RestAdapter.LogLevel.NONE)

Podemos personalizar la salida del método añadiendo una instancia de la classe Log

.setLog(new RestAdapter.Log() {...})
@Override
public void log(String message) { ... }

 

Configurar peticiones

Definición

Podemos modificar las peticiones mediante una serie de annotaciones:

@FormUrlEncoded
@Multipart
@Headers("Cache-Control: max-age=640000")
@Headers({
 "Accept: application/vnd.github.v3.full+json",
 "User-Agent: Retrofit-Sample-App"
})
Ejecución

Por otro lado, podemos interceptar las peticiones, para poder modificar todas y cada una de ellas de una sola vez:

.setRequestInterceptor(new RequestInterceptor() {...})
@Override 
public void intercept(RequestFacade request) {
 request.addHeader("Accept", "application/json");
 request.addHeader("Authorization", "token " + token());
} ​​

 

By Bernat Borrás