[Spring HATEOAS] 유저 정보 관리에 적용해본 내용 정리
Spring HATEOAS(Hypermedia As The Engine Of Application State)는 RESTful 서비스에서 하이퍼미디어를 쉽게 구현할 수 있도록 도와주는 라이브러리입니다. 하이퍼미디어는 클라이언트가 서버의 리소스와 상호작용할 수 있는 링크를 포함하여, API의 탐색성을 높여줍니다.
Spring HATEOAS를 사용한 이유는 유저 정보가 많고, 대부분의 정보가 변경이 필요 했기 때문입니다. 화면에서는 각 기능에 대한 URL을 받아 쉽게 처리할 수 있어 클라이언트가 링크를 통해 API를 탐색하고, 작업을 수행할 수 있습니다.
유저 정보 관리가 더 효율적이고 직관적으로 관리할 수 있을 것 같아 Spring HATEOAS적용을 고려하고, 적용하게 되었습니다.
spring v 2.2.2사용
UserModel 클래스 정의
- RepresentationModel은 Spring HATEOAS에서 하이퍼미디어 링크를 추가할 수 있는 기본 클래스입니다.
public class UserModel extends RepresentationModel<UserModel> {
private String id;
private String imgUrl;
private String nickName;
private Boolean isLogin;
// 생략..
// Getters and Setters
}
UserService 클래스 정의
- 유저 정보를 조회해 UserModel로 변환 합니다.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User findUserById(String id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));
}
public List<User> findAllUsers() {
return userRepository.findAll();
}
public UserModel getUserModel(String id) {
User user = findUserById(id);
UserModel model = new UserModel();
model.setId(user.getId());
//..
Class<UserRestController> controllerClass = UserRestController.class;
model.add(linkTo(methodOn(controllerClass).getUser(id)).withSelfRel());
model.add(linkTo(methodOn(controllerClass).editNickName(id, null)).withRel("nick-name"));
if (model.getIsLogin()) {
model.add(linkTo(methodOn(KickRestController.class).kickId(id)).withRel("user-kick")
.withType("confirm")
.withName("KICK")
.withTitle("유저를 강퇴하시겠습니까?" + user.getId()));
}
//..
return model;
}
}
단일 리소스를 반환할 때는 EntityModel 클래스를 사용하고, 여러 리소스를 반환할 때는 CollectionModel 클래스를 사용합니다. UserModel을 EntityModel과 CollectionModel로 변환하는 방법을 살펴보겠습니다.
EntityModel
@GetMapping("/user/{id}")
public EntityModel<UserModel> getUser(@PathVariable String id) {
UserModel userModel = userService.getUserModel(id);
return new EntityModel<>(userModel);
}
CollectionModel
@GetMapping("/users")
public CollectionModel<EntityModel<UserModel>> getAllUsers() {
List<User> users = userService.findAllUsers();
List<EntityModel<UserModel>> userModels = users.stream()
.map(user -> {
UserModel userModel = new UserModel();
userModel.setId(user.getId());
userModel.setProfileUrl(user.getProfileUrl());
userModel.setNickName(user.getNickName());
userModel.setIsLogin(user.isLogin());
EntityModel<UserModel> entityModel = new EntityModel<>(userModel);
entityModel.add(linkTo(methodOn(UserRestController.class).getUser(user.getId())).withSelfRel());
return entityModel;
})
.collect(Collectors.toList());
return new CollectionModel(userModels);
}
응답 JSON에 _links 필드가 추가되어 관련 링크 정보를 포함하게 됩니다
예시)
{
"_links" : {
"self" : { "href" : "..." },
"nickName" : { "href" : "..." }
}
}
정리.
- 링크 추가: HATEOAS의 핵심은 리소스에 관련 링크를 추가하는 것입니다. 이를 통해 클라이언트가 API의 다른 부분을 탐색할 수 있도록 합니다. Spring HATEOAS에서는 Link 클래스와 WebMvcLinkBuilder를 사용하여 링크를 생성하고 리소스에 추가할 수 있습니다.
- linkTo와 methodOn 메서드를 사용하여 링크를 작성합니다. ex) editNickName 메서드
- RepresentationModel 사용: Spring HATEOAS는 리소스를 표현하기 위해 RepresentationModel 클래스를 제공합니다. 이 클래스를 상속받아 리소스 모델을 만들고, 링크를 추가하여 클라이언트에게 전달할 수 있습니다.
+) RepresentationModelAssemblerSupport
RepresentationModelAssemblerSupport를 확장하여 UserModel을 EntityModel로 변환하는 어셈블러 클래스를 작성하면 작성해야 하는 코드 양을 줄이는 데 도움이 됩니다.
https://docs.spring.io/spring-hateoas/docs/current/reference/html/#mediatypes
https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/EntityModel.html