紹介するイントロ

Feignの紹介

1. 概要

このチュートリアルでは、Netflixによって開発されたFeign,宣言型HTTPクライアントを紹介して説明します。

Feignは、HTTP APIクライアントを簡素化することを目的としています。 簡単に言えば、開発者はインターフェイスを宣言して注釈を付けるだけで、実際の実装は実行時にプロビジョニングされます。

2. 例

FeignHTTPクライアントに基づいてクエリおよびテストされる書店サービスREST APIの例を示します。

サンプルのFeignクライアントを構築する前に、必要な依存関係を追加し、RESTサービスを起動します。

書店サービスの例は、hereから複製できます。

サービスアプリケーションをダウンロードしたら、次のコマンドで実行します。

$> mvn install spring-boot:run

3. セットアップ

まず、新しいMavenプロジェクトを作成し、次の依存関係を含めます。


    io.github.openfeign
    feign-okhttp
    9.3.1


    io.github.openfeign
    feign-gson
    9.3.1


    io.github.openfeign
    feign-slf4j
    9.3.1

feign-coreの依存関係(これもプルされます)に加えて、いくつかのプラグインを使用します。特に、Square’s OkHttpクライアントを内部的に使用してリクエストを行うためのfeign-okhttpfeign-gson for Google’s GSONJSONプロセッサとして使用し、feign-slf4jを使用してリクエストをログに記録します。

実際にログ出力を取得するには、クラスパスにSLF4Jでサポートされているお気に入りのロガー実装が必要です。

クライアントインターフェースの作成を続ける前に、データを保持するためのBookモデルを設定します。

public class Book {
    private String isbn;
    private String author;
    private String title;
    private String synopsis;
    private String language;

    // standard constructor, getters and setters
}

NOTE:JSONプロセッサには、少なくとも「引数なしのコンストラクタ」が必要です。

実際、RESTプロバイダーはhypermedia-driven API,であるため、単純なラッパークラスが必要になります。

public class BookResource {
    private Book book;

    // standard constructor, getters and setters
}

Note:サンプルのFeignクライアントはハイパーメディア機能の恩恵を受けていないため、llはBookResourceを単純に保ちます。

4. サーバ側

Feignクライアントを定義する方法を理解するために、まず、RESTプロバイダーでサポートされているメソッドと応答のいくつかを調べます。

簡単なcurlシェルコマンドを使用して、すべての本を一覧表示してみましょう。 呼び出しの前に‘/api'を付けることを忘れないでください。これは、application.propertiesで定義されているservlet-contextです。

$> curl http://localhost:8081/api/books

JSONとして表される完全な本のリポジトリを取得します。

[
  {
    "book": {
      "isbn": "1447264533",
      "author": "Margaret Mitchell",
      "title": "Gone with the Wind",
      "synopsis": null,
      "language": null
    },
    "links": [
      {
        "rel": "self",
        "href": "http://localhost:8081/api/books/1447264533"
      }
    ]
  },

  ...

  {
    "book": {
      "isbn": "0451524934",
      "author": "George Orwell",
      "title": "1984",
      "synopsis": null,
      "language": null
    },
    "links": [
      {
        "rel": "self",
        "href": "http://localhost:8081/api/books/0451524934"
      }
    ]
  }
]

ISBNをgetリクエストに追加することで、個々のBookリソースをクエリすることもできます。

$> curl http://localhost:8081/api/books/1447264533

5. 偽のクライアント

次に、Feignクライアントを定義します。

@RequestLineアノテーションを使用して、HTTP verbとパス部分を引数として指定し、パラメーターは@Paramアノテーションを使用してモデル化されます。

public interface BookClient {
    @RequestLine("GET /{isbn}")
    BookResource findByIsbn(@Param("isbn") String isbn);

    @RequestLine("GET")
    List findAll();

    @RequestLine("POST")
    @Headers("Content-Type: application/json")
    void create(Book book);
}

NOTE: Feignクライアントは、テキストベースのHTTP APIのみを使用するために使用できます。つまり、バイナリデータを処理できません。 ファイルのアップロードまたはダウンロード。

That’s all!次に、Feign.builder()を使用してインターフェイスベースのクライアントを構成します。 実際の実装は、実行時にプロビジョニングされます。

BookClient bookClient = Feign.builder()
  .client(new OkHttpClient())
  .encoder(new GsonEncoder())
  .decoder(new GsonDecoder())
  .logger(new Slf4jLogger(BookClient.class))
  .logLevel(Logger.Level.FULL)
  .target(BookClient.class, "http://localhost:8081/api/books");

Feignは、JSON /XMLエンコーダーとデコーダー、または要求を行うための基盤となるHTTPクライアントなどのさまざまなプラグインをサポートします。

6. 単体テスト

クライアントをテストするために、3つの@Testメソッドを含む単体テストクラスを作成しましょう。 テストでは、パッケージorg.hamcrest.CoreMatchers.*およびorg.junit.Assert.*からの静的インポートを使用します。

@Test
public void givenBookClient_shouldRunSuccessfully() throws Exception {
   List books = bookClient.findAll().stream()
     .map(BookResource::getBook)
     .collect(Collectors.toList());

   assertTrue(books.size() > 2);
}

@Test
public void givenBookClient_shouldFindOneBook() throws Exception {
    Book book = bookClient.findByIsbn("0151072558").getBook();
    assertThat(book.getAuthor(), containsString("Orwell"));
}

@Test
public void givenBookClient_shouldPostBook() throws Exception {
    String isbn = UUID.randomUUID().toString();
    Book book = new Book(isbn, "Me", "It's me!", null, null);
    bookClient.create(book);
    book = bookClient.findByIsbn(isbn).getBook();

    assertThat(book.getAuthor(), is("Me"));
}

これらのテストは一目瞭然です。 それを実行するには、Maventestのゴールを実行するだけです。

$> mvn test

7. 参考文献

何らかのフォールバックが必要な場合、サービスが利用できない場合は、HystrixFeignclasspathに追加し、代わりにHystrixFeign.builder()を使用してクライアントを構築できます。

Hystrixの詳細については、this dedicated tutorial seriesに従ってください。

Spring Cloud Netflix HystrixFeignと統合する場合は、このhereの詳細を読むことができます。

クライアント側の負荷分散やサービス検出をクライアントに追加することもできます。

前者は、クラスパスにRibbonを追加し、次のようにビルダーを呼び出すことによって行われます。

BookClient bookClient = Feign.builder()
  .client(RibbonClient.create())
  .target(BookClient.class, "http://localhost:8081/api/books");

サービス検出では、Spring Cloud Netflix Eurekaを有効にしてサービスを構築する必要があります。 次に、Spring Cloud Netflix Feignと統合するだけで、Ribbonの負荷分散を無料で利用できます。 これについての詳細はhereで見つけることができます。

8. 結論

この記事では、Feignを使用して宣言型HTTPクライアントを構築し、テキストベースのAPIsを使用する方法について説明しました。

いつものように、ソースon GitHubが見つかります。