Spring Data REST API の自動生成 (Neo4j)

このガイドでは、ハイパーメディアベースの RESTful フロントエンドを介してグラフベースのデータにアクセスするアプリケーションを作成するプロセスについて説明します。

構築するもの

Spring Data REST を使用して、Neo4j (英語) NoSQL データベースに格納されている Person オブジェクトを作成および取得できる Spring アプリケーションを構築します。Spring Data REST は Spring HATEOASSpring Data Neo4j の機能を取り、自動的に組み合わせます。

Spring Data REST は、バックエンドデータストアとして Spring Data JPASpring Data GemfireSpring Data MongoDB もサポートしますが、このガイドでは Neo4j を扱います。

必要なもの

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

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

最初から始めるには、[ スクラッチ ] に進みます。

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

完了したときは、{project_id}/complete のコードに対して結果を確認できます。

Neo4j サーバーを立ち上げる

このアプリケーションを構築する前に、Neo4j サーバーをセットアップする必要があります。

Neo4j には、フリーでインストールできるオープンソースサーバーがあります。

Homebrew がインストールされた Mac では、ターミナルウィンドウで次のように入力できます。

$ brew install neo4j

他のオプションについては、https://neo4j.com/download/community-edition/ (英語) を参照してください

Neo4j をインストールしたら、次のコマンドを実行して、デフォルト設定で Neo4j を起動できます。

$ neo4j start

次のようなメッセージが表示されます。

Starting Neo4j.
Started neo4j (pid 96416). By default, it is available at http://localhost:7474/
There may be a short delay until the server is ready.
See /usr/local/Cellar/neo4j/3.0.6/libexec/logs/neo4j.log for current status.

デフォルトでは、Neo4j のユーザー名とパスワードは neo4j と neo4j です。ただし、新しいアカウントのパスワードを変更する必要があります。これを行うには、次のコマンドを実行します。

$ curl -v -u neo4j:neo4j POST localhost:7474/user/neo4j/password -H "Content-type:application/json" -d "{\"password\":\"secret\"}"

これにより、パスワードが neo4j から secret に変更されます(本番環境ではしないこと! )これが完了すると、このガイドを実行する準備が整います。

Spring Initializr から開始

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

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

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

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

  3. 依存関係をクリックし、Rest リポジトリSpring Data Neo4j を選択します。

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

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

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

Neo4j へのアクセス許可

Neo4j Community エディションにアクセスするには資格情報が必要です。次のように、src/main/resources/application.properties でプロパティを設定することにより、資格情報を設定できます。

spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=secret

これには、デフォルトのユーザー名(neo4j)および以前に設定した新しく設定されたパスワード(secret)が含まれます。

実際の資格情報をソースリポジトリに保存しないでください。代わりに、Spring Boot のプロパティのオーバーライドを使用してランタイムで構成します。

ドメインオブジェクトを作成する

次の例(src/main/java/com/example/accessingneo4jdatarest/Person.java)に示すように、新しいドメインオブジェクトを作成して人物を提示する必要があります。

package com.example.accessingneo4jdatarest;

import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.GeneratedValue;

@Node
public class Person {

  @Id @GeneratedValue private Long id;

  private String firstName;
  private String lastName;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

Person オブジェクトには、名と姓があります。また、自動的に生成されるように構成されている ID オブジェクトもあり、そうする必要はありません。

Person リポジトリを作成する

次に、次の例(src/main/java/com/example/accessingneo4jdatarest/PersonRepository.java)が示すように、単純なリポジトリを作成する必要があります。

package com.example.accessingneo4jdatarest;

import java.util.List;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long>, CrudRepository<Person, Long> {

  List<Person> findByLastName(@Param("name") String name);

}

このリポジトリはインターフェースであり、Person オブジェクトに関連するさまざまな操作を実行できます。Spring Data Commons で定義された PagingAndSortingRepositry (Javadoc) インターフェースを継承することにより、これらの操作を取得します。

実行時に、Spring Data REST はこのインターフェースの実装を自動的に作成します。次に、@RepositoryRestResource (Javadoc) アノテーションを使用して、Spring MVC に /people で RESTful エンドポイントを作成するように指示します。

@RepositoryRestResource は、リポジトリのエクスポートには必要ありません。/persons のデフォルト値の代わりに /people を使用するなど、エクスポートの詳細を変更するためにのみ使用されます。

ここでは、lastName 値に基づいて Person オブジェクトのリストを取得するカスタムクエリも定義しました。このガイドの後半で呼び出す方法を確認できます。

アプリケーションクラスの検索

Spring Initializr を使用してプロジェクトを作成すると、アプリケーションクラスが作成されます。src/main/java/com/example/accessingneo4jdatarest/Application.java で見つけることができます。Spring Initializr はパッケージ名を連結(および大文字小文字を適切に変更)し、Application に追加してアプリケーションケース名を作成することに注意してください。この場合、次のように、AccessingNeo4jDataRestApplication を取得します。

package com.example.accessingneo4jdatarest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@EnableNeo4jRepositories
@SpringBootApplication
public class AccessingNeo4jDataRestApplication {

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

この例では、このアプリケーションクラスに変更を加える必要はありません。

@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 であり、接続機能やインフラストラクチャの構成に対処する必要はありませんでした。

@EnableNeo4jRepositories アノテーションは Spring Data Neo4j をアクティブにします。Spring Data Neo4j は、PersonRepository の具体的な実装を作成し、Cypher クエリ言語を使用して組み込みの Neo4j データベースと通信するように構成します。

実行可能 JAR を構築する

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

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

java -jar build/libs/{project_id}-0.1.0.jar

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

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

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

アプリケーションをテストする

アプリケーションが実行されたため、テストできます。任意の REST クライアントを使用できます。次の例では、curl という *nix ツールを使用しています。

最初に、最上位のサービスを表示します。次の例(出力あり)は、その方法を示しています。

$ curl http://localhost:8080
{
  "_links" : {
    "people" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    }
  }
}

ここでは、このサーバーが提供するものを最初に垣間見ることができます。http://localhost:8080/people に people リンクがあります。?page?size?sort などのいくつかのオプションがあります。

Spring Data REST は、JSON 出力に HAL フォーマット (英語) を使用します。これは柔軟性があり、提供されるデータに隣接するリンクを提供する便利な方法を提供します。
$ curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

現在、要素もページも存在しないため、新しい Person を作成します。これを行うには、次のコマンドを実行します(出力とともに表示)。

$ curl -i -X POST -H "Content-Type:application/json" -d '{  "firstName" : "Frodo",  "lastName" : "Baggins" }' http://localhost:8080/people
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/people/0
Content-Length: 0
Date: Wed, 26 Feb 2014 20:26:55 GMT
  • -i は、ヘッダーを含むレスポンスメッセージを確認できるようにします。新しく作成された Person の URI が表示されます

  • -X POST は、新しいエントリの作成に使用される POST を通知します

  • -H "Content-Type:application/json" は、ペイロード型に JSON オブジェクトが含まれていることをアプリケーションが認識するようにコンテンツ型を設定します

  • -d '{ "firstName" : "Frodo", "lastName" : "Baggins" }' は送信されるデータです

前の POST 操作に Location ヘッダーが含まれていることに注目してください。これには、新しく作成されたリソースの URI が含まれます。Spring Data REST には、作成されたばかりのリソースの表現をすぐに返すようにフレームワークを構成するために使用できる 2 つのメソッド (RepositoryRestConfiguration.setReturnBodyOnCreate(…) および setReturnBodyOnCreate(…)) もあります。

これから、次のコマンドを実行することにより、すべてのユーザーを照会できます(出力とともに表示)。

$ curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/0"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

people オブジェクトには、Frodo のリストが含まれています。self リンクがどのように含まれているかに注目してください。Spring Data REST も Evo Inflector (英語) ライブラリを使用して、グループ化のためにエンティティの名前を複数形にします。

次のコマンドを実行することで、個々のレコードを直接照会できます(出力とともに表示)。

$ curl http://localhost:8080/people/0
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/0"
    }
  }
}
これは純粋に Web ベースのように見えるかもしれませんが、裏では Neo4j グラフデータベースが組み込まれています。本番環境では、おそらくスタンドアロン Neo4j サーバーに接続します。

このガイドでは、ドメインオブジェクトは 1 つだけです。ドメインオブジェクトが互いに関連しているより複雑なシステムでは、Spring Data REST は接続されたレコードに移動するのに役立つ追加のリンクを表示します。

次のコマンドを実行すると、すべてのカスタムクエリを見つけることができます(出力とともに表示)。

$ curl http://localhost:8080/people/search
{
  "_links" : {
    "findByLastName" : {
      "href" : "http://localhost:8080/people/search/findByLastName{?name}",
      "templated" : true
    }
  }
}

HTTP クエリパラメーター name を含むクエリの URL を確認できます。これは、インターフェースに埋め込まれた @Param("name") アノテーションと一致することに注意してください。

findByLastName クエリを使用するには、次のコマンドを実行します(出力とともに表示)。

$ curl http://localhost:8080/people/search/findByLastName?name=Baggins
{
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/0"
        },
        "person" : {
          "href" : "http://localhost:8080/people/0"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/search/findByLastName?name=Baggins"
    }
  }
}

コードで List<Person> を返すように定義しているため、すべての結果が返されます。Person のみを返すように定義している場合、Person オブジェクトの 1 つを選択して返します。これは予測できないため、複数のエントリを返す可能性のあるクエリに対してはそうしたくないでしょう。

PUTPATCHDELETE REST 呼び出しを発行して、既存のレコードを置換、更新、削除することもできます。次の例(出力とともに表示)は、PUT 呼び出しを示しています。

$ curl -X PUT -H "Content-Type:application/json" -d '{ "firstName": "Bilbo", "lastName": "Baggins" }' http://localhost:8080/people/0
$ curl http://localhost:8080/people/0
{
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/0"
    }
  }
}

次の例(出力とともに表示)は、PATCH 呼び出しを示しています。

$ curl -X PATCH -H "Content-Type:application/json" -d '{ "firstName": "Bilbo Jr." }' http://localhost:8080/people/0
$ curl http://localhost:8080/people/0
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/0"
    }
  }
}
PUT はレコード全体を置き換えます。指定されていないフィールドは null に置き換えられます。PATCH を使用して、アイテムのサブセットを更新できます。

次の例に示すように、レコードを削除することもできます(出力とともに表示)。

$ curl -X DELETE http://localhost:8080/people/0
$ curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

このハイパーメディア駆動型インターフェースの便利な側面は、curl(または任意の REST クライアント)を使用して、すべての RESTful エンドポイントを検出する方法です。正式な契約書やインターフェースドキュメントを顧客と交換する必要はありません。

要約

おめでとう! ハイパーメディアベースの RESTful フロントエンドと Neo4j ベースのバックエンドを備えたアプリケーションを開発しました。

コードを入手する