리팩토링
이전 게시글에서 작성한 코드에도 물론 문제가 있다. 지금까지의 코드는 Post 그 자체를 응답으로 주고있다.
만약 클라이언트에서 json 응답에 title 엔 10글자까지만 달라는 요청을 한다면?
Post 에서 아래처럼 getter 매서드를 재정의 하면 되지 않을까?
Post
여기서 getter 를 재정의 하는 이유는 데이터를 객체로 역직렬화 할때도 썼던 Jackson 라이브러리의 동작 방식에 있다.
Jackson 라이브러리에서 객체를 JSON 으로 직렬화 할 때 getter 를 사용하여 데이터를 맵핑해주기 때문이다.
따라서 이렇게 getTitle 을 재정의하면 원하는대로 10글자까지만 응답으로 내려갈 것이다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@Lob // java 에선 String 이지만 DB 에선 long text 형태로 생성되게 해줌
private String content;
@Builder
public Post(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title.substring(0, Math.min(10, title.length());
}
}
PostServiceTest
@DisplayName("JSON 응답에 제목은 12글자 까지만 제한")
@Test
void get2() throws Exception {
// given
Post post = Post.builder()
.title("우리 이쁜 미카공주님")
.content("우리 공주님")
.build();
postRepository.save(post);
// expected
mockMvc.perform(
MockMvcRequestBuilders.get("/posts/{postId}", post.getId())
.contentType(APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(post.getId()))
.andExpect(jsonPath("$.title").value("우리 이쁜 미카공주님"))
.andExpect(jsonPath("$.content").value("우리 공주님"))
.andDo(print());
}
결과는 역시 10글자까지만 나온다.
하지만 이런 식으로 수정 시 이후에 추가될 기능과 충돌할 가능성이 있으므로 지양해야한다.
서비스 정책에 맞는 응답 클래스로 분리하라
응답으로 Post 엔티티를 그대로 반환하는게 아닌 응답용 PostResponse 객체를 만들어서
그곳에서 서비스 정책에서 원하는대로 데이터를 가공해서 응답으로 반환하는것이 바람직한 방법이다.
PostResponse
이 객체에서 10글자까지 자르는 로직을 수행한다.
@Getter
public class PostResponse {
private final long id;
private final String title;
private final String content;
@Builder
public PostResponse(long id, String title, String content) {
this.id = id;
this.title = title.substring(0, Math.min(title.length(), 10));
this.content = content;
}
}
PostService
Post 를 PostResponse 로 전환해서 컨트롤러로 반환한다.
이걸 전환하는 위치에 대해서도 논란이 많은데 우선은 간단하게 이렇게 구현하겠다.
public PostResponse get(Long id) {
Post post = postRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("존재하지 않는 글입니다.")
);
PostResponse response = PostResponse.builder()
.id(post.getId())
.title(post.getTitle())
.content(post.getContent())
.build();
return response;
}
PostServiceTest
테스트는 맨 위에서 작성한 예시 테스트와 동일하고, 결과는 역시 하는대로 10글자까지만 나온다.
PostController
@GetMapping("/posts/{postId}")
public PostResponse get(@PathVariable(name = "postId") Long id) {
return postService.get(id);
}
요구사항이 변경되으니 컨트롤러, 서비스 테스트 또한 변경된 요구사항에 맞춰 수정해야 한다.
변경사항이 적용된 테스트 코드는 따로 올리지는 않겠다.
결론
엔티티 그 자체를 응답으로 반환하면 API 요구 스펙이 바뀔 때 변경에 유연하지 않다.
따라서 서비스 요구사항에 맞는 Response 객체를 만들어 반환하라.
'API 만들어 보기 > 게시판 API' 카테고리의 다른 글
[게시글 조회] 페이징 처리 1 (0) | 2023.09.25 |
---|---|
[게시글 조회] 게시글 여러개 조회 (0) | 2023.09.24 |
[게시글 조회] 단건 조회 (0) | 2023.09.23 |
[작성글 저장] 리팩토링 1 (0) | 2023.09.23 |
[작성글 저장] 게시글 저장 구현 (1) | 2023.09.22 |