인프런 - 스프링 부트와 JPA 활용2 by 김영한 을 기반으로 작성된 글입니다.
실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
//회원 등록 API - v1
@PostMapping("/api/v1/members")
public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){
Long id = memberService.join(member);
return new CreateMemberResponse(id);
}
@Data
static class CreateMemberResponse{
//등록된 id 값만 반환
private Long id;
public CreateMemberResponse(Long id) {
this.id = id;
}
}
API 어노테이션
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {}
name : hello
send
로직 확인
(city, street, zipcode 는 입력하지 않았기 때문에 null)
그러나 데이터를 입력하지 않고 send 해도 null로 데이터가 입력된다
Member Entity에 따로 제약조건을 걸어둔 것이 없기 때문이다
@Entity
@Getter @Setter
public class Member {
(생략)
@NotEmpty
private String name;
}
Member Entity의 name 컬럼에 @NotEmpty 제약조건 추가 후
데이터 입력하지 않고 send 하면 Springboot에서 기본으로 설정해놓은 에러 발생
CreateMemberResponse()의 @Vaild
가 javax.validation 을 검증 한다
Member Entity의 name 컬럼에 @NotEmpty
검증
@NotEmpty
등)이 들어간다Presentation(표현)계층을 위한 검증 로직이 Entity에 모두 들어가 있다
사용하는 API에 따라 @NotEmpty
의 필요 유무가 다르기 때문에 문제가 발생한다
💡 해결
API 스펙을 위한 별도의 DTO(Data Transfer Object)를 생성하여 파라미터로 받아야한다 - 아래 V2에서 해결
중요!
API를 만들 때 항상 엔티티를 파라미터로 받지 마라
엔티티를 웹에 노출하지 말아라
//회원 등록 API - v2
@PostMapping("/api/v2/members")
public CreateMemberResponse saveMemberV1(@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{
@NotEmpty
private String name;
}
ex. Member Entity의 name 컬럼명이 username으로 변경되었을 때
setter 부분만 변경해주면 해결된다. API가 영향을 받지 않는다.
파라미터와 엔티티를 Controller에서 매핑해주는 것
Member member = new Member();
member.setUsername(request.getName());
엔티티를 외부에 노출하지 않고 API에 맞는 별도의 객체 DTO를 생성하여 만드는 것이 좋다