HATEOAS でハイパーメディア駆動 REST API の作成

このガイドでは、Spring で "Hello, World" ハイパーメディア駆動型 REST Web サービスを作成するプロセスを順を追って説明します。

ハイパーメディア [Wikipedia] (英語) は REST の重要な側面です。これにより、クライアントとサーバーを大幅に分離し、独立して進化させるサービスを構築できます。REST リソースに対して返される表現には、データだけでなく、関連リソースへのリンクも含まれます。表現の設計はサービス全体の設計にとって重要です。

構築するもの

Spring HATEOAS を使用してハイパーメディア駆動型の REST サービスを構築します。これは、Spring MVC コントローラーを指すリンクを作成し、リソース表現を構築し、サポートされているハイパーメディア形式 (HAL など) にレンダリングする方法を制御するために使用できる API のライブラリです。

サービスは http://localhost:8080/greeting で HTTP GET リクエストを受け入れます。

これは、可能な限り単純なハイパーメディア要素、リソース自体を指すリンクで強化された挨拶の JSON 表現で応答します。次のリストに出力を示します。

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
    }
  }
}

次のように、レスポンスはクエリ文字列にオプションの name パラメーターを使用してグリーティングをカスタマイズできることをすでに示しています。

http://localhost:8080/greeting?name=User

name パラメーター値は、次のように、World のデフォルト値をオーバーライドし、レスポンスに反映されます。

{
  "content":"Hello, User!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=User"
    }
  }
}

必要なもの

本ガイドの完成までの流れ

ほとんどの Spring 入門ガイドと同様に、最初から始めて各ステップを完了するか、すでに慣れている場合は基本的なセットアップステップをバイパスできます。いずれにしても、最終的に動作するコードになります。

最初から始めるには、Spring Initializr から開始に進みます。

基本スキップするには、次の手順を実行します。

完了したときは、gs-rest-hateoas/complete のコードに対して結果を確認できます。

Spring Initializr から開始

IDE を使用する場合はプロジェクト作成ウィザードを使用します。IDE を使用せずにコマンドラインなどで開発する場合は、この事前に初期化されたプロジェクトからプロジェクトを ZIP ファイルとしてダウンロードできます。このプロジェクトは、このチュートリアルの例に合うように構成されています。

プロジェクトを手動で初期化するには:

  1. IDE のメニューまたはブラウザーから Spring Initializr を開きます。アプリケーションに必要なすべての依存関係を取り込み、ほとんどのセットアップを行います。

  2. Gradle または Maven のいずれかと、使用する言語を選択します。このガイドは、Java を選択したことを前提としています。

  3. 依存関係をクリックして、Spring HATEOAS を選択します。

  4. 生成をクリックします。

  5. 結果の ZIP ファイルをダウンロードします。これは、選択して構成された Web アプリケーションのアーカイブです。

EclipseIntelliJ のような IDE は新規プロジェクト作成ウィザードから Spring Initializr の機能が使用できるため、手動での ZIP ファイルのダウンロードやインポートは不要です。
プロジェクトを Github からフォークして、IDE または他のエディターで開くこともできます。

リソース表現クラスを作成する

プロジェクトとビルドシステムをセットアップしたため、Web サービスを作成できます。

サービスの相互作用について考えることでプロセスを開始します。

サービスは、/greeting でリソースを公開し、GET リクエストを処理します。オプションで、クエリ文字列に name パラメーターを使用します。GET リクエストは、挨拶を表すために本文に JSON を含む 200 OK レスポンスを返す必要があります。

さらに、リソースの JSON 表現は、_links プロパティのハイパーメディア要素のリストで強化されます。これの最も基本的な形式は、リソース自体を指すリンクです。表現は次のようになります。

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
    }
  }
}

content は、挨拶のテキスト表現です。_links エレメントには、リンクのリストが含まれます(この場合、リレーション型が rel で、アクセスされたリソースを指す href 属性を持つものだけです)。

あいさつ表現をモデル化するには、リソース表現クラスを作成します。_links プロパティは表現モデルの基本的なプロパティであるため、Spring HATEOAS には、Link のインスタンスを追加し、前に示したようにレンダリングされるようにする基本クラス(RepresentationModel と呼ばれる)が付属しています。

次のリスト(src/main/java/com/example/resthateoas/Greeting.java から)が示すように、RepresentationModel を継承し、コンテンツのフィールドとアクセッサ、コンストラクターを追加するプレーンな古い java オブジェクトを作成します。

package com.example.resthateoas;

import org.springframework.hateoas.RepresentationModel;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Greeting extends RepresentationModel<Greeting> {

	private final String content;

	@JsonCreator
	public Greeting(@JsonProperty("content") String content) {
		this.content = content;
	}

	public String getContent() {
		return content;
	}
}
  • @JsonCreator: Jackson がこの POJO のインスタンスを作成する方法を通知します。

  • @JsonProperty: Jackson がこのコンストラクター引数を配置するフィールドをマークします。

このガイドで後述するように、Spring は Jackson JSON ライブラリを使用して、型 Greeting のインスタンスを JSON に自動的にマーシャリングします。

次に、これらのグリーティングを提供するリソースコントローラーを作成します。

REST コントローラーを作成する

RESTful Web サービスを構築する Spring のアプローチでは、HTTP リクエストはコントローラーによって処理されます。コンポーネントは、@RestController (Javadoc) アノテーションによって識別されます。これは、@Controller (Javadoc) アノテーションと @ResponseBody (Javadoc) アノテーションを組み合わせたものです。次の GreetingController (src/main/java/com/example/resthateoas/GreetingController.java から)は、Greeting クラスの新しいインスタンスを返すことにより、/greeting に対する GET リクエストを処理します。

package com.example.resthateoas;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@RestController
public class GreetingController {

	private static final String TEMPLATE = "Hello, %s!";

	@RequestMapping("/greeting")
	public HttpEntity<Greeting> greeting(
		@RequestParam(value = "name", defaultValue = "World") String name) {

		Greeting greeting = new Greeting(String.format(TEMPLATE, name));
		greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());

		return new ResponseEntity<>(greeting, HttpStatus.OK);
	}
}

このコントローラーは簡潔でシンプルですが、多くのことを示しています。段階的に分解していきましょう。

@RequestMapping アノテーションは、/greeting への HTTP リクエストが greeting() メソッドにマップされることを保証します。

上記の例では、@RequestMapping はデフォルトですべての HTTP 操作をマップするため、GET と PUTPOST などは指定されていません。@GetMapping("/greeting") を使用して、このマッピングを絞り込みます。その場合は、import org.springframework.web.bind.annotation.GetMapping; も必要です。

@RequestParam は、クエリ文字列パラメーター name の値を greeting() メソッドの name パラメーターにバインドします。defaultValue 属性を使用しているため、このクエリ文字列パラメーターは暗黙的に required ではありません。リクエストにない場合、World の defaultValue が使用されます。

クラスに @RestController アノテーションが存在するため、暗黙的な @ResponseBody (Javadoc) アノテーションが greeting メソッドに追加されます。これにより、Spring MVC は返された HttpEntity とそのペイロード ( Greeting) をレスポンスに直接レンダリングします。

メソッド実装の最も興味深い部分は、コントローラーメソッドを指すリンクを作成する方法と、それを表現モデルに追加する方法です。linkTo(…) と methodOn(…) はどちらも ControllerLinkBuilder の静的メソッドであり、コントローラーでメソッド呼び出しを偽装できます。返された LinkBuilder は、コントローラーメソッドのマッピングアノテーションをインスペクションして、メソッドがマッピングされる URI を正確に構築します。

Spring HATEOAS は、さまざまな X-FORWARDED- ヘッダーを考慮します。Spring HATEOAS サービスをプロキシの背後に配置し、X-FORWARDED-HOST ヘッダーを使用して適切に構成すると、結果のリンクは適切にフォーマットされます。

withSelfRel() を呼び出すと、Link インスタンスが作成され、Greeting 表現モデルに追加されます。

@SpringBootApplication は、次のすべてを追加する便利なアノテーションです。

  • @Configuration: アプリケーションコンテキストの Bean 定義のソースとしてクラスにタグを付けます。

  • @EnableAutoConfiguration: クラスパス設定、他の Bean、さまざまなプロパティ設定に基づいて Bean の追加を開始するよう Spring Boot に指示します。例: spring-webmvc がクラスパスにある場合、このアノテーションはアプリケーションに Web アプリケーションとしてフラグを立て、DispatcherServlet のセットアップなどの主要な動作をアクティブにします。

  • @ComponentScan: Spring に、com/example パッケージ内の他のコンポーネント、構成、サービスを探して、コントローラーを検出させるように指示します。

main() メソッドは、Spring Boot の SpringApplication.run() メソッドを使用してアプリケーションを起動します。XML が 1 行もないことに気付きましたか? web.xml ファイルもありません。この Web アプリケーションは 100% 純粋な Java であり、接続機能やインフラストラクチャの構成に対処する必要はありませんでした。

実行可能 JAR を構築する

コマンドラインから Gradle または Maven を使用してアプリケーションを実行できます。必要なすべての依存関係、クラス、リソースを含む単一の実行可能 JAR ファイルを構築して実行することもできます。実行可能な jar を構築すると、開発ライフサイクル全体、さまざまな環境などで、アプリケーションとしてサービスを簡単に提供、バージョン管理、デプロイできます。

Gradle を使用する場合、./gradlew bootRun を使用してアプリケーションを実行できます。または、次のように、./gradlew build を使用して JAR ファイルをビルドしてから、JAR ファイルを実行できます。

java -jar build/libs/gs-rest-hateoas-0.1.0.jar

Maven を使用する場合、./mvnw spring-boot:run を使用してアプリケーションを実行できます。または、次のように、./mvnw clean package で JAR ファイルをビルドしてから、JAR ファイルを実行できます。

java -jar target/gs-rest-hateoas-0.1.0.jar
ここで説明する手順は、実行可能な JAR を作成します。クラシック WAR ファイルを作成することもできます。

ロギング出力が表示されます。サービスは数秒以内に起動して実行されるはずです。

サービスをテストする

サービスが起動したら、http://localhost:8080/greeting にアクセスして、次のコンテンツを確認します。

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
    }
  }
}

次の URL にアクセスして、name クエリ文字列パラメーターを指定します: http://localhost:8080/greeting?name=User 次のように、content 属性の値が Hello, World! から Hello, User! にどのように変化し、self リンクの href 属性にもその変化が反映されることに注意してください。

{
  "content":"Hello, User!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=User"
    }
  }
}

この変更は、GreetingController の @RequestParam 配置が期待どおりに機能することを示しています。name パラメーターには World のデフォルト値が指定されていますが、クエリ文字列を介して常に明示的にオーバーライドできます。

要約

おめでとう! Spring HATEOAS を使用してハイパーメディア駆動型の RESTfulWeb サービスを開発しました。

コードを入手する