1. 概要

これまでのところ、クラウドアプリケーションでは、ゲートウェイパターンを使用して2つの主要な機能をサポートしてきました。

まず、クライアントを各サービスから隔離し、クロスオリジンサポートの必要性を排除しました。 次に、Eurekaを使用してサービスのインスタンスの検索を実装しました。

この記事では、ゲートウェイパターンを使用して単一のリクエストで複数のサービスからデータを取得する方法を見ていきます。 これを行うために、Feignをゲートウェイに導入して、サービスへのAPI呼び出しの記述を支援します。

Feignクライアントの使用方法については、この記事をご覧ください。

Spring Cloudは、このパターンを実装する Spring CloudGatewayプロジェクトも提供するようになりました。

2. 設定

Gatewayサーバーのpom.xmlを開き、Feignの依存関係を追加しましょう。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

参考までに– Maven Central spring-cloud-starter-feign )で最新バージョンを見つけることができます。

Feignクライアントの構築がサポートされたので、GatewayApplicationで有効にします。java

@EnableFeignClients
public class GatewayApplication { ... }

それでは、本と評価サービス用にFeignクライアントを設定しましょう。

3. 偽のクライアント

3.1. ブッククライアント

BooksClient。javaという新しいインターフェイスを作成しましょう。

@FeignClient("book-service")
public interface BooksClient {
 
    @RequestMapping(value = "/books/{bookId}", method = RequestMethod.GET)
    Book getBookById(@PathVariable("bookId") Long bookId);
}

このインターフェースを使用して、「 / books /{bookId}」エンドポイントにアクセスするFeignクライアントを作成するようにSpringに指示しています。 呼び出されると、 getBookById メソッドはエンドポイントへのHTTP呼び出しを行い、bookIdパラメーターを使用します。

これを機能させるには、 Book.javaDTOを追加する必要があります。

@JsonIgnoreProperties(ignoreUnknown = true)
public class Book {
 
    private Long id;
    private String author;
    private String title;
    private List<Rating> ratings;
    
    // getters and setters
}

RatingsClientに移りましょう。

3.2. 評価クライアント

RatingsClientというインターフェイスを作成しましょう。

@FeignClient("rating-service")
public interface RatingsClient {
 
    @RequestMapping(value = "/ratings", method = RequestMethod.GET)
    List<Rating> getRatingsByBookId(
      @RequestParam("bookId") Long bookId, 
      @RequestHeader("Cookie") String session);
    
}

BookClient と同様に、ここで公開されているメソッドは、評価サービスにREST呼び出しを行い、書籍の評価のリストを返します。

ただし、このエンドポイントは保護されています。 このエンドポイントに正しくアクセスできるようにするには、ユーザーのセッションをリクエストに渡す必要があります。

これは、@RequestHeaderアノテーションを使用して行います。 これにより、Feignはその変数の値をリクエストのヘッダーに書き込むように指示されます。 この例では、Spring SessionがCookie内のセッションを検索するため、Cookieヘッダーに書き込みます。

この例では、Spring SessionがCookie内のセッションを検索するため、Cookieヘッダーに書き込みます。

最後に、Ratingを追加しましょう。java DTO:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Rating {
    private Long id;
    private Long bookId;
    private int stars;
}

これで、両方のクライアントが完成しました。 それらを使ってみましょう!

4. 複合リクエスト

ゲートウェイパターンの一般的なユースケースの1つは、一般的に呼ばれるサービスをカプセル化するエンドポイントを持つことです。 これにより、クライアントリクエストの数を減らすことで、パフォーマンスを向上させることができます。

これを行うには、コントローラーを作成してCombinedController。javaと呼びます。

@RestController
@RequestMapping("/combined")
public class CombinedController { ... }

次に、新しく作成した偽のクライアントを接続しましょう。

private BooksClient booksClient;
private RatingsClient ratingsClient;

@Autowired
public CombinedController(
  BooksClient booksClient, 
  RatingsClient ratingsClient) {
 
    this.booksClient = booksClient;
    this.ratingsClient = ratingsClient;
}

最後に、これら2つのエンドポイントを組み合わせて、評価が読み込まれた1冊の本を返すGETリクエストを作成しましょう。

@GetMapping
public Book getCombinedResponse(
  @RequestParam Long bookId,
  @CookieValue("SESSION") String session) {
 
    Book book = booksClient.getBookById(bookId);
    List<Rating> ratings = ratingsClient.getRatingsByBookId(bookId, "SESSION="+session);
    book.setRatings(ratings);
    return book;
}

リクエストからセッション値を抽出する@CookieValueアノテーションを使用してセッション値を設定していることに注意してください。

そこにそれがある! ゲートウェイには、クライアントとシステム間のネットワーク呼び出しを減らす複合エンドポイントがあります。

5. テスト

新しいエンドポイントが機能していることを確認しましょう。

LiveTest。javaに移動し、結合されたエンドポイントのテストを追加しましょう。

@Test
public void accessCombinedEndpoint() {
    Response response = RestAssured.given()
      .auth()
      .form("user", "password", formConfig)
      .get(ROOT_URI + "/combined?bookId=1");
 
    assertEquals(HttpStatus.OK.value(), response.getStatusCode());
    assertNotNull(response.getBody());
 
    Book result = response.as(Book.class);
 
    assertEquals(new Long(1), result.getId());
    assertNotNull(result.getRatings());
    assertTrue(result.getRatings().size() > 0);
}

Redisを起動し、アプリケーションで各サービスを実行します: config、discovery、zipkin、 gateway book 、およびrating サービス。

すべてが稼働したら、新しいテストを実行して、機能していることを確認します。

6. 結論

Feignをゲートウェイに統合して、専用のエンドポイントを構築する方法を見てきました。 この情報を活用して、サポートする必要のあるAPIを構築できます。 最も重要なことは、個々のリソースのみを公開する万能APIにとらわれていないことです。

ゲートウェイパターンを使用して、各クライアントのニーズに合わせてゲートウェイサービスを独自に設定できます。 これにより、デカップリングが作成され、サービスが必要に応じて自由に進化できるようになり、無駄がなく、アプリケーションの1つの領域に集中できます。

いつものように、コードスニペットはGitHubで見つけることができます。