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-okhttp、feign-gson for Google’s GSONをJSONプロセッサとして使用し、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. 参考文献
何らかのフォールバックが必要な場合、サービスが利用できない場合は、HystrixFeignをclasspathに追加し、代わりにHystrixFeign.builder()を使用してクライアントを構築できます。
Hystrixの詳細については、this dedicated tutorial seriesに従ってください。
Spring Cloud Netflix HystrixをFeignと統合する場合は、この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が見つかります。