1. 概要

Retrofit は、Square( Dagger Okhttp )によって開発されたAndroidおよびJava用のタイプセーフなHTTPクライアントです。

この記事では、最も興味深い機能に焦点を当てて、レトロフィットの使用方法を説明します。 特に、同期APIと非同期API、認証、ロギング、およびいくつかの優れたモデリング手法での使用方法について説明します。

2. 例の設定

まず、RetrofitライブラリとGsonコンバーターを追加します。

<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>retrofit</artifactId>
    <version>2.3.0</version>
</dependency>  
<dependency>  
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>converter-gson</artifactId>
    <version>2.3.0</version>
</dependency>

最新バージョンについては、MavenCentralリポジトリのRetrofitおよびconverter-gsonを参照してください。

3. APIモデリング

RetrofitはRESTエンドポイントをJavaインターフェースとしてモデル化し、理解と利用を非常に簡単にします。

GitHubのユーザーAPIをモデル化します。 これには、JSON形式でこれを返すGETエンドポイントがあります。

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

Retrofitは、ベースURLをモデル化し、インターフェイスがRESTエンドポイントからエンティティを返すようにすることで機能します。

簡単にするために、 User クラスをモデル化して、JSONのごく一部を取得します。このクラスは、値を受け取ったときに値を取得します。

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

    // standard getters an setters

}

この例では、プロパティのサブセットのみを取得していることがわかります。 Retrofitは、プロパティの欠落について文句を言いません。必要なものだけをマップするため、JSONにないプロパティを追加しても文句を言いません。

これで、インターフェイスモデリングに移り、Retrofitアノテーションのいくつかを説明できます。

public interface UserService {

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

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

注釈付きのメタデータは、ツールが機能する実装を生成するのに十分です。

@GET アノテーションは、使用するHTTPメソッドとリソースをクライアントに通知します。たとえば、「https://api.github.com」のベースURLを指定すると、リクエストが次のアドレスに送信されます。 「https://api.github.com/users」。

相対URLの先頭の「/」は、それがホスト上の絶対パスであることをRetrofitに通知します。

もう1つの注意点は、完全にオプションの @Query パラメーターを使用することです。これらのパラメーターは、必要ない場合はnullとして渡すことができ、値がない場合はツールがこれらのパラメーターを無視します。

最後になりましたが、 @Path では、パスで使用したマークアップの代わりに配置されるパスパラメーターを指定できます。

4. 同期/非同期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();

Retrofitは、必要なオブジェクトを作成するための便利なビルダーを提供します。 すべてのサービス呼び出しに使用されるベースURLとコンバーターファクトリが必要です。これは、送信するデータの解析と取得する応答を処理します。

この例では、 GsonConverterFactory を使用します。これにより、JSONデータが前に定義したUserクラスにマップされます。

ファクトリが異なれば目的も異なることに注意することが重要です。したがって、ファクトリをXML、プロトバッファに使用したり、カスタムプロトコル用に作成したりすることもできることに注意してください。 すでに実装されているファクトリのリストについては、こちらをご覧ください。

最後の依存関係は OKHttpClient –これはAndroidおよびJavaアプリケーション用のHTTPおよびHTTP/2クライアントです。 これにより、サーバーへの接続と情報の送信と取得が処理されます。 また、すべての呼び出しにヘッダーとインターセプターを追加することもできます。これについては、認証セクションで確認します。

Retrofitオブジェクトができたので、サービスコールを作成できます。これを同期的に行う方法を見てみましょう。

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

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

ここでは、以前の注釈に基づいて、リクエストを行うために必要なコードを挿入することにより、Retrofitがサービスインターフェイスの構築をどのように処理するかを確認できます。

その後、 電話 GitHubAPIへのリクエストを実行するために使用されるオブジェクト。 ここで最も重要なメソッドはexecuteです。これは、呼び出しを同期的に実行するために使用され、データの転送中に現在のスレッドをブロックします。

呼び出しが正常に実行された後、 GsonConverterFactory のおかげで、応答の本文(すでにユーザーオブジェクト上にある)を取得できます。

同期呼び出しを行うのは非常に簡単ですが、通常、非ブロッキング非同期要求を使用します。

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

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

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

ここで、executeメソッドの代わりに、 エンキューメソッド–これは折り返し電話リクエストの成功または失敗を処理するためのパラメータとしてのインターフェース。 これは別のスレッドで実行されることに注意してください。

呼び出しが正常に終了した後、以前と同じ方法で本文を取得できます。

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> S createService(Class<S> serviceClass) {
        return retrofit.create(serviceClass);
    }
}

Retrofitオブジェクトを作成するすべてのロジックは、この GitHubServiceGenerator クラスに移動されました。これにより、コードの繰り返しを防ぐ持続可能なクライアントクラスになります。

使い方の簡単な例を次に示します。

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

たとえば、 RepositoryService、を作成する場合、このクラスを再利用して作成を簡素化できます。

次のセクションでは、それを拡張し、認証機能を追加します。

6. 認証

ほとんどのAPIには、アクセスを保護するための認証があります。

以前のジェネレータークラスを考慮して、Authorizationヘッダーを持つJWTトークンを受け取るcreateserviceメソッドを追加します。

public static <S> S createService(Class<S> 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、ユーザー/パスワードなどの任意の認証を使用できることに注意してください。

7. ロギング

このセクションでは、ログ機能のために GitHubServiceGenerator をさらに拡張します。これは、すべてのプロジェクトのデバッグ目的で非常に重要です。

インターセプターに関する以前の知識を使用しますが、追加の依存関係が必要です。これは、OkHttpの HttpLoggingInterceptor であり、pom.xmlに追加します。

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>logging-interceptor</artifactId>
    <version>3.9.0</version>
</dependency>

次に、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> S createService(Class<S> serviceClass) {
        if (!httpClient.interceptors().contains(logging)) {
            httpClient.addInterceptor(logging);
            builder.client(httpClient.build());
            retrofit = builder.build();
        }
        return retrofit.create(serviceClass);
    }

    public static <S> S createService(Class<S> 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 を追加した方法を確認できます。これを基本ログに設定します。これにより、リクエスト、エンドポイント、ステータスの作成にかかった時間がログに記録されます。リクエストごとなど

インターセプターが存在するかどうかを確認する方法を確認することが重要です。これにより、誤ってインターセプターを2回追加することはありません。

8. 結論

この広範なガイドでは、Sync / Async API、モデリング、認証、およびロギングのいくつかのベストプラクティスに焦点を当てて、優れたRetrofitライブラリを確認しました。

ライブラリは非常に複雑で便利な方法で使用できます。 RxJavaの高度な使用例については、このチュートリアルをご覧ください。

そして、いつものように、ソースコードはGitHubにあります。