SpringアプリケーションのJSON API
1. 概要
2. メーベン
まず、Mavenの構成を見てみましょう。次の依存関係をpom.xmlに追加する必要があります。
io.katharsis
katharsis-spring
3.0.2
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 {}
4. リソースリポジトリ
次に、リソースリポジトリについて説明します。各リソースには、使用可能なAPI操作を公開するためのResourceRepositoryV2が必要です。
@Component
public class UserResourceRepository implements ResourceRepositoryV2 {
@Autowired
private UserRepository userRepository;
@Override
public User findOne(Long id, QuerySpec querySpec) {
return userRepository.findOne(id);
}
@Override
public ResourceList findAll(QuerySpec querySpec) {
return querySpec.apply(userRepository.findAll());
}
@Override
public ResourceList findAll(Iterable ids, QuerySpec querySpec) {
return querySpec.apply(userRepository.findAll(ids));
}
@Override
public S save(S entity) {
return userRepository.save(entity);
}
@Override
public void delete(Long id) {
userRepository.delete(id);
}
@Override
public Class getResourceClass() {
return User.class;
}
@Override
public S create(S entity) {
return save(entity);
}
}
ここで簡単に説明します–これはもちろんvery similar to a Spring controllerです。
5. カタルシス構成
katharsis-springを使用しているため、必要なのは、Spring BootアプリケーションにKatharsisConfigV3をインポートすることだけです。
@Import(KatharsisConfigV3.class)
そして、application.propertiesでカタルシスパラメータを設定します。
katharsis.domainName=http://localhost:8080
katharsis.pathPrefix=/
これで、APIの使用を開始できます。例えば:
-
GET“http://localhost:8080/users“:すべてのユーザーを取得します。
-
POST“http://localhost:8080/users“:新しいユーザーを追加するなど。
6. 関係
次に、JSONAPIでエンティティの関係を処理する方法について説明します。
6.1. 役割リソース
まず、新しいリソース–Roleを紹介しましょう。
@JsonApiResource(type = "roles")
public class Role {
@JsonApiId
private Long id;
private String name;
@JsonApiRelation
private Set users;
}
次に、UserとRoleの間に多対多の関係を設定します。
@JsonApiRelation(serialize=SerializeType.EAGER)
private Set roles;
6.2. ロールリソースリポジトリ
非常に迅速–これがRoleリソースリポジトリです:
@Component
public class RoleResourceRepository implements ResourceRepositoryV2 {
@Autowired
private RoleRepository roleRepository;
@Override
public Role findOne(Long id, QuerySpec querySpec) {
return roleRepository.findOne(id);
}
@Override
public ResourceList findAll(QuerySpec querySpec) {
return querySpec.apply(roleRepository.findAll());
}
@Override
public ResourceList findAll(Iterable ids, QuerySpec querySpec) {
return querySpec.apply(roleRepository.findAll(ids));
}
@Override
public S save(S entity) {
return roleRepository.save(entity);
}
@Override
public void delete(Long id) {
roleRepository.delete(id);
}
@Override
public Class getResourceClass() {
return Role.class;
}
@Override
public S create(S entity) {
return save(entity);
}
}
ここで理解することが重要なのは、この単一のリソースリポジトリは、別のリポジトリを使用する関係の側面を処理しないということです。
6.3. リレーションシップリポジトリ
User –Role間の多対多の関係を処理するには、新しいスタイルのリポジトリを作成する必要があります。
@Component
public class UserToRoleRelationshipRepository implements RelationshipRepositoryV2 {
@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 roleIds, String fieldName) {
Set roles = new HashSet();
roles.addAll(roleRepository.findAll(roleIds));
user.setRoles(roles);
userRepository.save(user);
}
@Override
public void addRelations(User user, Iterable roleIds, String fieldName) {
Set roles = user.getRoles();
roles.addAll(roleRepository.findAll(roleIds));
user.setRoles(roles);
userRepository.save(user);
}
@Override
public void removeRelations(User user, Iterable roleIds, String fieldName) {
Set 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 findManyTargets(Long sourceId, String fieldName, QuerySpec querySpec) {
User user = userRepository.findOne(sourceId);
return querySpec.apply(user.getRoles());
}
@Override
public Class getSourceResourceClass() {
return User.class;
}
@Override
public Class getTargetResourceClass() {
return Role.class;
}
}
ここでは、リレーションシップリポジトリ内の単一のメソッドを無視しています。
7. Test
最後に、いくつかのリクエストを分析して、JSON-API出力がどのように見えるかを実際に理解しましょう。
単一のユーザーリソース(id = 2)の取得を開始します。
{
"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にあります
-
リソースの主な関係はdata.relationshipsにあります
-
rolesの関係に@JsonApiRelation(serialize=SerializeType.EAGER)を使用したため、JSONに含まれ、ノードincludedにあります。
次へ–ロールを含むコレクションリソースを取得しましょう。
{
"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ノードの配列として取得することです。
8. 結論
JSON-APIは素晴らしい仕様です。最後に、APIでJSONを使用する方法で構造を追加し、真のハイパーメディアAPIを実際に強化しています。
この記事では、Springアプリで設定する1つの方法を検討しました。 しかし、その実装に関係なく、仕様自体は「私の見解では」非常に非常に有望な作業です。
この例の完全なソースコードは、on GitHubで入手できます。 これは、そのままインポートして実行できるMavenプロジェクトです。