Введение в модернизацию

Введение в модернизацию

1. обзор

Retrofit - это типобезопасный HTTP-клиент для Android и Java, разработанный Square (Dagger,Okhttp).

В этой статье мы собираемся объяснить, как использовать Retrofit, уделив особое внимание его наиболее интересным функциям. В частности, мы обсудим синхронный и асинхронный API, как использовать его с аутентификацией, ведением журнала и некоторыми передовыми методами моделирования.

2. Настройка примера

Начнем с добавления библиотеки Retrofit и конвертера Gson:


    com.squareup.retrofit2
    retrofit
    2.3.0


    com.squareup.retrofit2
    converter-gson
    2.3.0

Последние версии см. ВRetrofit иconverter-gson в репозитории Maven Central.

3. Моделирование API

Модифицировать модели конечных точек REST как интерфейсов Java, что делает их очень простыми для понимания и использования.

Мы смоделируемuser API из GitHub; у этого есть конечная точкаGET, которая возвращает это в формате JSON:

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

Модернизация работает путем моделирования по базовому URL и создания интерфейсов, возвращающих сущности из конечной точки REST.

Для простоты мы возьмем небольшую часть JSON, смоделировав наш классUser, который будет принимать значения, когда мы их получим:

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

    // standard getters an setters

}

Мы видим, что в этом примере мы берем только подмножество свойств. Retrofit won’t complain about missing properties – since it only maps what we need, он даже не будет жаловаться, если мы добавим свойства, которых нет в JSON.

Теперь мы можем перейти к моделированию интерфейса и объяснить некоторые аннотации 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);
}

Метаданных, снабженных аннотациями, достаточно, чтобы инструмент генерировал рабочие реализации.

Аннотация@GET сообщает клиенту, какой HTTP-метод использовать и на каком ресурсе, поэтому, например, предоставив базовый URL-адрес «https://api.github.com», он отправит запрос на «https: //api.github.com/users ».

Начальный знак «/» в нашем относительном URLtells Retrofit that it is an absolute path on the host.

Также следует отметить, что мы используем полностью необязательные параметры@Query, которые можно передавать как null, если они нам не нужны. Инструмент позаботится об игнорировании этих параметров, если они не имеют значений.

И последнее, но не менее важное:@Path позволяет нам указать параметр пути, который будет помещен вместо разметки, которую мы использовали в пути.

4. Synchronous/Asynchronous API

Чтобы создать вызов HTTP-запроса, нам нужно сначала построить наш объект Retrofit:

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

Модернизация предоставляет удобную конструкцию для строительства необходимого нам объекта. It needs the base URL which is going to be used for every service call and a converter factory - отвечает за анализ отправляемых нами данных и получаемых ответов.

В этом примере мы собираемся использоватьGsonConverterFactory, который будет отображать наши данные JSON с классомUser, который мы определили ранее.

Важно отметить, что разные фабрики служат разным целям, поэтому имейте в виду, что мы также можем использовать фабрики для XML, прото-буферов или даже создать фабрики для собственного протокола. Список уже реализованных фабрик можно найти вhere.

Последняя зависимость -OKHttpClient - клиент HTTP и HTTP / 2 для приложений Android и Java. Это будет заботиться о соединении с сервером и отправке и поиске информации. Мы также могли бы добавить заголовки и перехватчики для каждого вызова, что мы увидим в нашем разделе аутентификации.

Теперь, когда у нас есть объект Retrofit, мы можем создать вызов службы, давайте посмотрим, как это сделать синхронным способом:

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

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

Здесь мы можем увидеть, как Retrofit заботится о построении интерфейса нашего сервиса, внедряя код, необходимый для выполнения запроса, основываясь на наших предыдущих аннотациях.

После этого мы получаем объектCall<User>, который используется для выполнения запроса к GitHub API. The most important method here is execute,, который используется для синхронного выполнения вызова и блокирует текущий поток при передаче данных.

После успешного выполнения вызова мы можем получить тело ответа - уже в пользовательском объекте - благодаря нашемуGsonConverterFactory.

Выполнить синхронный вызов очень просто, но обычно мы используем неблокирующий асинхронный запрос:

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);
    }
});

Теперь вместо метода execute мы используем методenqueue, который принимает синтерфейсCallback<User>в качестве параметра для обработки успешного или неудачного выполнения запроса. Обратите внимание, что это будет выполняться в отдельном потоке.

После успешного завершения вызова мы можем получить тело так же, как и раньше.

5. Создание многоразового классаServiceGenerator

Теперь, когда мы увидели, как создать наш объект Retrofit и как использовать API, мы видим, что не хотим писать конструктор снова и снова.

Нам нужен класс многократного использования, который позволяет нам создать этот объект один раз и повторно использовать его в течение всего срока службы нашего приложения:

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);
    }
}

Вся логика создания объекта Retrofit теперь перенесена в этот классGitHubServiceGenerator, что делает его устойчивым клиентским классом, который предотвращает повторение кода.

Вот простой пример того, как его использовать:

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

Теперь, если бы мы, например, создалиRepositoryService,, мы могли бы повторно использовать этот класс и упростить создание.

In the next section, мы собираемся расширить его и добавить возможности аутентификации.

6. Аутентификация

Большинство API имеют некоторую аутентификацию для безопасного доступа к ней.

Принимая во внимание наш предыдущий класс генератора, мы собираемся добавить метод создания службы, который принимает токен JWT с заголовкомAuthorization:

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);
}

Чтобы добавить заголовок к нашему запросу, нам нужно использовать возможности перехватчикаOkHttp; мы делаем это, используя наш ранее определенный конструктор и реконструируя объект Retrofit.

Обратите внимание, что это простой пример аутентификации, но с использованием перехватчиков мы можем использовать любую аутентификацию, такую ​​как OAuth, user / password и т. Д.

7. логирование

В этом разделе мы собираемся расширить нашGitHubServiceGenerator для возможности ведения журнала, что очень важно для целей отладки в каждом проекте.

Мы собираемся использовать наши предыдущие знания о перехватчиках, но нам нужна дополнительная зависимость, которая представляет собойHttpLoggingInterceptor от OkHttp, давайте добавим ее к нашемуpom.xml:


    com.squareup.okhttp3
    logging-interceptor
    3.9.0

Теперь давайте расширим наш классGitHubServiceGenerator:

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);
    }
}

Это последняя форма нашего класса, мы можем видеть, как мы добавилиHttpLoggingInterceptor, и мы установили его для базового ведения журнала, который будет регистрировать время, необходимое для выполнения запроса, конечную точку, статус для каждого запрос и др.

Важно посмотреть, как мы проверяем, существует ли перехватчик, чтобы случайно не добавить его дважды.

8. Заключение

В этом обширном руководстве мы рассмотрели превосходную библиотеку Retrofit, сосредоточившись на ее Sync / Async API, некоторых лучших практиках моделирования, аутентификации и ведения журналов.

Библиотеку можно использовать очень сложными и полезными способами; для расширенного варианта использования RxJava, пожалуйста, посмотритеthis tutorial.

И, как всегда, исходный код можно найтиover on GitHub.