❌ 잘못된 방법 ( 요청 값으로 Member 엔티티를 직접 받음. )
@PostMapping("/api/v1/members")
public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member)
{
Long id = memberService.join(member);
return new CreateMemberResponse(id);
}
여러 곳에서 수정될 가능성이 있는 Entity가 바뀜으로 인해서
만들어놓은 api스펙이 변경될 수 있도록 하면 안된다.
-> ⭕️ API 요청 스펙에 맞추어 별도의 DTO를 파라미터로 받는다.
-> 파라미터로 넘어오는 값이 무엇인지 확실히 알 수 있음 !
-> 유지보수에 유리함.
@PostMapping("/api/v2/members")
public CreateMemberResponse saveMemberV2(@RequestBody @Valid
CreateMemberRequest request) {
Member member = new Member();
member.setName(request.getName());
Long id = memberService.join(member);
return new CreateMemberResponse(id);
}
@Data
static class CreateMemberRequest {
private String name;
}
❗️❗️ 실무에서는 엔티티를 API 스펙에 노출하면 안된다!
회원 조회와 똑같이 DTO를 요청 파라미터에 넘겨준다.
@PostMapping("/api/v2/members/{id}") // 부분 업데이트를 하려면 post나 patch를 사용하는 것이 restful한 방법.
public UpdateMemberResponse updateMemberV2(@PathVariable("id") Long id, @RequestBody @Valid UpdateMemberRequest request) {
memberService.update(id, request.getName());
Member findMember = memberService.findOne(id); // 커맨드와 쿼리를 구분하기 위한 코드
return new UpdateMemberResponse(findMember.getId(), findMember.getName());
}
public class MemberService {
private final MemberRepository memberRepository;
// 변경 감지를 이용해서 데이터 수정함.
@Transactional
public void update(Long id, String name) {
Member member = memberRepository.findOne(id);
member.setName(name);
}
}
🔴 다양한 API 요구에 따라서 유연하게 데이터를 주고받기 위해서
응답 값으로 엔티티를 직접 외부에 노출하지 않고,
별도의 DTO를 반환해야 한다.
@GetMapping("/api/v2/members")
public Result membersV2() {
List<Member> findMembers = memberService.findMembers(); // 엔티티 -> DTO 변환
List<MemberDto> collect = findMembers.stream()
.map(m -> new MemberDto(m.getName()))
.collect(Collectors.toList());
return new Result(collect); // 컬렉션을 감싸서 향후 필요한 필드 추가 가능
}
@Data
@AllArgsConstructor
static class Result<T> {
private T data;
}
Application.yml
에서
ddl-auto:None
위 코드 추가
-> 한번 데이터를 넣어놓으면 테이블을 들어가지 않고 계속해서 db에 있는 데이터들을 쓸 수 있다.