Zuulプロキシを使ったSpring REST

Zuulプロキシを使用したSpring REST

1. 概要

この記事では、communication between a front-end application and a REST API that are deployed separatelyについて説明します。

目標は、ブラウザのCORSと同一生成元ポリシーの制限を回避し、同じオリジンを共有していなくてもUIがAPIを呼び出せるようにすることです。

基本的に、UIアプリケーションと単純なREST APIの2つの別個のアプリケーションを作成し、UIアプリケーションでthe Zuul proxyを使用してRESTAPIへの呼び出しをプロキシします。

Zuulは、NetflixによるJVMベースのルーターおよびサーバー側のロードバランサーです。 また、Spring Cloudには、組み込みのZuulプロキシとの優れた統合があります。これをここで使用します。

参考文献:

ZuulとEurekaを使用した負荷分散の例

Netflix Zuulでの負荷分散の様子をご覧ください。

Spring REST APIを使用したSwagger 2のセットアップ

Swagger 2を使用してSpring REST APIを文書化する方法を学びます。

Spring RESTドキュメントの概要

この記事では、正確で読みやすいRESTfulサービスのドキュメントを生成するテスト駆動メカニズムであるSpring REST Docsを紹介します。

2. Mavenの構成

まず、Spring CloudからUIアプリケーションのpom.xmlへのzuulサポートへの依存関係を追加する必要があります。


    org.springframework.cloud
    spring-cloud-starter-zuul
    1.0.4.RELEASE

3. ズールの特性

次に、Zuulを構成する必要があります。また、Spring Bootを使用しているため、application.ymlで構成します。

zuul:
  routes:
    foos:
      path: /foos/**
      url: http://localhost:8081/spring-zuul-foos-resource/foos

ご了承ください:

4. API

APIアプリケーションは、シンプルなSpring Bootアプリです。

この記事では、on port 8081.を実行しているサーバーにデプロイされたAPIについて検討します。

まず、使用するリソースの基本的なDTOを定義しましょう。

public class Foo {
    private long id;
    private String name;

    // standard getters and setters
}

そしてシンプルなコントローラー:

@Controller
public class FooController {

    @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}")
    @ResponseBody
    public Foo findById(
      @PathVariable long id, HttpServletRequest req, HttpServletResponse res) {
        return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4));
    }
}

5. UIアプリケーション

UIアプリケーションは、単純なSpring Bootアプリケーションでもあります。

この記事では、on port 8080.を実行しているサーバーにデプロイされたAPIについて検討します。

AngularJSを少し使用して、メインのindex.htmlから始めましょう。








Foo Details

{{foo.id}} {{foo.name}} New Foo

ここで最も重要な側面は、APIusing relative URLs!にアクセスする方法です。

APIアプリケーションはUIアプリケーションと同じサーバーso relative URLs shouldn’t workにデプロイされておらず、プロキシがないと機能しないことに注意してください。

ただし、プロキシを使用すると、Zuulプロキシを介してFooリソースにアクセスします。これは、もちろん、APIが実際にデプロイされている場所にこれらのリクエストをルーティングするように構成されています。

そして最後に、実際にブート可能なアプリケーション:

@EnableZuulProxy
@SpringBootApplication
public class UiApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(UiApplication.class, args);
    }
}

単純なBootアノテーションに加えて、Zuulプロキシにもenableスタイルのアノテーションを使用していることに注意してください。これは非常にクールでクリーンで簡潔です。

6. ルーティングをテストする

それでは、UIアプリケーションを次のようにテストしてみましょう。

@Test
public void whenSendRequestToFooResource_thenOK() {
    Response response = RestAssured.get("http://localhost:8080/foos/1");

    assertEquals(200, response.getStatusCode());
}

7. カスタムズールフィルター

利用可能なZuul filtersは複数あり、独自のカスタムを作成することもできます。

@Component
public class CustomZuulFilter extends ZuulFilter {

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.addZuulRequestHeader("Test", "TestSample");
        return null;
    }

    @Override
    public boolean shouldFilter() {
       return true;
    }
    // ...
}

この単純なフィルターは、「Test」というヘッダーをリクエストに追加するだけですが、もちろん、ここでリクエストを拡張するために必要なだけ複雑になる可能性があります。

8. カスタムズールフィルターをテストする

最後に、カスタムフィルタが機能していることをテストしてみましょう。最初に、FoosリソースサーバーでFooControllerを変更します。

@Controller
public class FooController {

    @GetMapping("/foos/{id}")
    @ResponseBody
    public Foo findById(
      @PathVariable long id, HttpServletRequest req, HttpServletResponse res) {
        if (req.getHeader("Test") != null) {
            res.addHeader("Test", req.getHeader("Test"));
        }
        return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4));
    }
}

それでは、テストしてみましょう。

@Test
public void whenSendRequest_thenHeaderAdded() {
    Response response = RestAssured.get("http://localhost:8080/foos/1");

    assertEquals(200, response.getStatusCode());
    assertEquals("TestSample", response.getHeader("Test"));
}

9. 結論

この記事では、Zuulを使用してUIアプリケーションからREST APIにリクエストをルーティングすることに焦点を当てました。 CORSおよび同一生成元ポリシーを回避することに成功し、送信中のHTTP要求をカスタマイズおよび拡張することもできました。

このチュートリアルのfull implementationは、the GitHub projectにあります。これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。