SpringアプリケーションのJSON API

1概要

この記事では、http://jsonapi.org/[JSON-API]仕様** と、それをSpringでサポートされているREST APIに統合する方法について検討します。

JavaでJSON-APIのhttps://github.com/katharsis-project/katharsis-framework[Katharsis]実装を使用します - そしてKatharsisを使ったSpringアプリケーションをセットアップします - それで必要なのはSpringだけです。応用。

** 2メーベン

**

最初に、私たちのmaven設定を見てみましょう - 私たちの pom.xml に以下の依存関係を追加する必要があります。

<dependency>
    <groupId>io.katharsis</groupId>
    <artifactId>katharsis-spring</artifactId>
    <version>3.0.2</version>
</dependency>

3ユーザーリソース

次に、私たちのユーザーリソースを見てみましょう。

@JsonApiResource(type = "users")
public class User {

    @JsonApiId
    private Long id;

    private String name;

    private String email;
}

ご了承ください:

  • @ JsonApiResource アノテーションは、リソース User を定義するために使用されています

  • @ JsonApiId アノテーションはリソース識別子を定義するために使用されます

そしてごく簡単に言うと、この例の永続性はここでSpring Dataリポジトリになるでしょう。

public interface UserRepository extends JpaRepository<User, Long> {}

4リソースリポジトリ

次に、リソースリポジトリについて説明しましょう。各リソースには、利用可能なAPIオペレーションを公開するための ResourceRepositoryV2 が必要です。

@Component
public class UserResourceRepository implements ResourceRepositoryV2<User, Long> {

    @Autowired
    private UserRepository userRepository;

    @Override
    public User findOne(Long id, QuerySpec querySpec) {
        return userRepository.findOne(id);
    }

    @Override
    public ResourceList<User> findAll(QuerySpec querySpec) {
        return querySpec.apply(userRepository.findAll());
    }

    @Override
    public ResourceList<User> findAll(Iterable<Long> ids, QuerySpec querySpec) {
        return querySpec.apply(userRepository.findAll(ids));
    }

    @Override
    public <S extends User> S save(S entity) {
        return userRepository.save(entity);
    }

    @Override
    public void delete(Long id) {
        userRepository.delete(id);
    }

    @Override
    public Class<User> getResourceClass() {
        return User.class;
    }

    @Override
    public <S extends User> S create(S entity) {
        return save(entity);
    }
}

ちょっと注意してください - これはもちろんSpringコントローラに非常によく似ています。

5カタサルシスの設定

katharsis-spring を使用しているので、Spring Bootアプリケーションに KatharsisConfigV3 をインポートするだけです。

@Import(KatharsisConfigV3.class)

そして、私たちの application.properties でKatharsisパラメータを設定します。

katharsis.domainName=http://localhost:8080
katharsis.pathPrefix=/----

これで -  APIを使い始めることができます。例えば:

**  GET“ __http://localhost:8080/users__“:すべてのユーザーを取得します。

**  POST“ __http://localhost:8080/users__“:新しいユーザーを追加するなど。

[[test]]

===  **  6. 関係**

次に、JSON APIでエンティティの関係を処理する方法について説明しましょう。

====  **  6.1. 役割リソース**

まず、新しいリソースを紹介しましょう -  __ロール__:

[source,java,gutter:,true]

@JsonApiResource(type = "roles") public class Role {

@JsonApiId
private Long id;
private String name;
    @JsonApiRelation
    private Set<User> users;
}
そして、__User__と__Role__の間に多対多の関係を設定します。

[source,java,gutter:,true]

@JsonApiRelation(serialize=SerializeType.EAGER) private Set<Role> roles;

====  **  6.2. 役割リソースリポジトリ**

非常に早く - ここに私たちの__Role__リソースリポジトリがあります:

[source,java,gutter:,true]

@Component public class RoleResourceRepository implements ResourceRepositoryV2<Role, Long> {

@Autowired
private RoleRepository roleRepository;
@Override
public Role findOne(Long id, QuerySpec querySpec) {
    return roleRepository.findOne(id);
}
@Override
public ResourceList<Role> findAll(QuerySpec querySpec) {
    return querySpec.apply(roleRepository.findAll());
}
@Override
public ResourceList<Role> findAll(Iterable<Long> ids, QuerySpec querySpec) {
    return querySpec.apply(roleRepository.findAll(ids));
}
@Override
public <S extends Role> S save(S entity) {
    return roleRepository.save(entity);
}
@Override
public void delete(Long id) {
    roleRepository.delete(id);
}
@Override
public Class<Role> getResourceClass() {
    return Role.class;
}
    @Override
    public <S extends Role> S create(S entity) {
        return save(entity);
    }
}
ここで理解することは重要です。この単一のリソースレポジトリはリレーションシップの側面を扱っていない - それは別のリポジトリを取ります。

====  **  6.3. 関係リポジトリ**

__ユーザー__ __ __ロール__間の多対多の関係を処理するために、新しいスタイルのリポジトリを作成する必要があります。

[source,java,gutter:,true]

@Component public class UserToRoleRelationshipRepository implements RelationshipRepositoryV2<User, Long, Role, Long> {

@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Override
public void setRelation(User User, Long roleId, String fieldName) {}
@Override
public void setRelations(User user, Iterable<Long> roleIds, String fieldName) {
    Set<Role> roles = new HashSet<Role>();
    roles.addAll(roleRepository.findAll(roleIds));
    user.setRoles(roles);
    userRepository.save(user);
}
@Override
public void addRelations(User user, Iterable<Long> roleIds, String fieldName) {
    Set<Role> roles = user.getRoles();
    roles.addAll(roleRepository.findAll(roleIds));
    user.setRoles(roles);
    userRepository.save(user);
}
@Override
public void removeRelations(User user, Iterable<Long> roleIds, String fieldName) {
    Set<Role> roles = user.getRoles();
    roles.removeAll(roleRepository.findAll(roleIds));
    user.setRoles(roles);
    userRepository.save(user);
}
@Override
public Role findOneTarget(Long sourceId, String fieldName, QuerySpec querySpec) {
    return null;
}
@Override
public ResourceList<Role> findManyTargets(Long sourceId, String fieldName, QuerySpec querySpec) {
    User user = userRepository.findOne(sourceId);
    return  querySpec.apply(user.getRoles());
}
@Override
public Class<User> getSourceResourceClass() {
    return User.class;
}
    @Override
    public Class<Role> getTargetResourceClass() {
        return Role.class;
    }
}
リレーションシップリポジトリでは、ここでは特異な方法を無視しています。

[[conclusion]]

===  **  7. テスト**

最後に、いくつかのリクエストを分析し、JSON-APIの出力がどのように見えるかを実際に理解しましょう。

単一のUserリソース(id = 2)の取得を始めます。

**  GET http://localhost:8080/users/2 **

[source,bash,gutter:,true]

{ "data":{ "type":"users", "id":"2", "attributes":{ "email":"[email protected]", "username":"tom" }, "relationships":{ "roles":{ "links":{ "self":"http://localhost:8080/users/2/relationships/roles", "related":"http://localhost:8080/users/2/roles" } } }, "links":{ "self":"http://localhost:8080/users/2" } }, "included":[ { "type":"roles", "id":"1", "attributes":{ "name":"ROLE__USER" }, "relationships":{ "users":{ "links":{ "self":"http://localhost:8080/roles/1/relationships/users", "related":"http://localhost:8080/roles/1/users" } } }, "links":{ "self":"http://localhost:8080/roles/1" } } ]}

お持ち帰り:

** リソースの主な属性は__ **  data.attributes **  __にあります。

** リソースの主な関係はにあります

__ ** データ関係**  __
**  __ @ JsonApiRelation(serialize = SerializeType.EAGER)__を使用したので

__ロール__関係、これはJSONに含まれ、ノード**  included ** にあります。

次に、ロールを含むコレクションリソースを取得しましょう。

**  GET http://localhost:8080/roles **

[source,bash,gutter:,true]

{ "data":[ { "type":"roles", "id":"1", "attributes":{ "name":"ROLE USER" }, "relationships":{ "users":{ "links":{ "self":"http://localhost:8080/roles/1/relationships/users", "related":"http://localhost:8080/roles/1/users" } } }, "links":{ "self":"http://localhost:8080/roles/1" } }, { "type":"roles", "id":"2", "attributes":{ "name":"ROLE ADMIN" }, "relationships":{ "users":{ "links":{ "self":"http://localhost:8080/roles/2/relationships/users", "related":"http://localhost:8080/roles/2/users" } } }, "links":{ "self":"http://localhost:8080/roles/2" } } ], "included":[ ]}

ここでのちょっとした問題は、システム内のすべてのロールを、**  data ** ノードの配列として取得することです

[[conclusion-1]]

===  **  8結論**

JSON-APIは素晴らしい仕様です。最後に、APIでJSONを使用する方法で何らかの構造を追加して、真のハイパーメディアAPIを実現します。

この記事では、Springアプリで設定するための1つの方法について説明しました。しかし、その実装に関係なく、仕様自体は - 私の考えでは非常に有望な作業です。

例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/spring-katharsis[GitHub]で入手可能です。インポートしてそのまま実行できるMavenプロジェクトです。