Zayson
A to Zayson!
Zayson
전체 방문자
오늘
어제
  • 분류 전체보기 (132)
    • Computer Science (20)
      • Network (4)
      • DB (12)
      • OS (4)
    • Algorithm (32)
      • 완전탐색(Brute-Force) (3)
      • 그리디(Greedy) (6)
      • 투포인터(Two-Pointer) (1)
      • 그래프(Graph) (5)
      • BFS & DFS (9)
      • 구현, 시뮬레이션(Implementation) (5)
      • 다이나믹 프로그래밍(DP) (3)
    • Backend (51)
      • Spring Boot (19)
      • JPA (16)
      • Kafka (2)
      • Java (13)
      • Kotlin (1)
    • DevOps (1)
      • Jenkins (5)
      • Oracle Cloud Infrastructure (1)
      • Kubernetes & Docker (1)
    • Trouble Shooting (3)
      • JPA (1)
      • Spring Boot (2)
    • 회고 (5)
      • 엔빵 프로젝트 포스트 로드맵 (1)
      • 2022년 (4)
    • Kafka (7)
      • Kafka (5)
      • Kafka Connect (2)
    • 기술 서적 (6)
      • 데이터 중심 애플리케이션 설계 (3)
      • 개발자가 반드시 정복해야할 객체 지향과 디자인 패턴 (2)
      • 가상 면접 사례로 배우는 대규모 시스템 설계 기초 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

태그

  • BFS
  • dfs
  • Computer science
  • 프로그래머스
  • kafka
  • 완전탐색
  • JPA
  • 나 혼자 스프링부트!
  • Java
  • 라이브스터디
  • 백준
  • Kafka Connect
  • Backend
  • 구현
  • SpringBoot
  • 엔빵프로젝트
  • CS
  • 관계형 데이터베이스 실전 입문
  • spring boot
  • 그리디

최근 글

티스토리

hELLO · Designed By 정상우.
Zayson

A to Zayson!

API 개발 기본 간단 정리
Backend/Spring Boot

API 개발 기본 간단 정리

2022. 7. 7. 12:14

“김영한 강사님의 JPA 활용편 2- API 개발과 성능 최적화"를 듣고 간단하게 정리하기”

 

  • @RestController는 기존 @Controller와 @ResponseBody가 합쳐진 형태이다.
  • @RequestBody는 JSON으로 들어온 데이터를 받은 객체로 매핑해서 변환해준다.
@PostMapping("/api/v1/members")
public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member) {
    Long id = memberService.join(member);
    return new CreateMemberResponse(id);
}
  • @Valid는 javax.validation을 검증한다.
@Entity
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    @NotEmpty // javax.validation
    private String name;

		... 
}
  • 위의 예제는 프레젠테이션 계층 (화면 - Controller)에서 들어온 데이터에 대한 검증 로직이 엔티티계층에 있는 경우이다.
  • 이러한 경우 API 별로 name에 대해 요구사항이 다른 경우(A는 name이 empty 가능, B는 불가능) 문제가 발생한다.
  • 또한 엔티티 컬럼을 변경하는 경우 API에 대한 스펙이 바뀌어버린다.
  • API 요청 스펙에 맞춰서 별도의 DTO를 만들어서 사용하고 검증해야한다. → 엔티티를 외부에 노출하지 말자! 엔티티 계층과 프레젠테이션 계층을 구분하자!
@Data
static class CreateMemberRequest{
    @NotEmpty
    private Stringname;
}

@Data
static class CreateMemberResponse{
    private Longid;

    public CreateMemberResponse(Long id){
        this.id= id;
    }
}
  • DTO를 사용해서 데이터를 요청받고 응답한다.
@PostMapping("ap1/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);
}

 

  • 엔티티의 수정은 변경감지를 사용한다. 예시는 setter를 사용하지만 setter가 아닌 의미있는 이름을 가진 메서드를 엔티티 계층에 넣어 생성하자!
@Transactional
public void update(Long id, String name) {
    Member member = memberRepository.findMember(id);
    member.setName(name);
}

 

  • 커맨드와 쿼리를 분리한다. Update는 엔티티의 데이터를 변경하는 커맨드 성 메서드, 조회는 쿼리성 메서드이다.
@PutMapping("api/v2/members/{id}")
public UpdateMemberResponse updateMemberV2(@PathVariable("id") Long id,
                                           @RequestBody @Valid UpdateMemberRequest request) {
    // update는 커맨드 메서드
    memberService.update(id, request.getName());
        
    // 조회는 쿼리 메서드
    Member member = memberService.findOne(id);

    return new UpdateMemberResponse(id, member.getName());
}

 

  • 엔티티를 직접 노출하는 경우 연관된 모든 데이터가 함께 노출된다. 엔티티에 @JsonIgnore를 사용해 제외할 수 도 있다.
@JsonIgnore
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();

 

  • 하지만 이 방법 역시 API 별로 요구사항이 다르기 때문에 엔티티에 녹이는 경우 문제가 발생할 수 있다.
  • 그리고 엔티티 데이터 이외에 다른 데이터도 함께 보내달라고 요구사항이 들어오는 경우 엔티티를 반환하면 응답값 자체를 바꿀 수가 없다.
  • 결국 DTO를 이용해서 처리하는 것이 정답이다!
@GetMapping("api/v2/members")
public Result memberV2() {
    List<Member> findMembers = memberService.findMembers();
    List<MemberDto> collect = findMembers.stream()
            .map(member -> new MemberDto(member.getName()))
            .collect(Collectors.toList());

    return new Result(collect);
}

@Data
@AllArgsConstructor
static class Result<T> {
    private T data;
}
반응형
저작자표시 비영리 변경금지 (새창열림)

'Backend > Spring Boot' 카테고리의 다른 글

[API 고급] 컬렉션 조회 최적화  (0) 2022.07.12
[API 개발 고급] 지연 로딩과 조회 성능 최적화  (0) 2022.07.07
도메인 개발 팁 간단 정리  (0) 2022.07.05
RestTemplate  (0) 2022.07.01
Converter를 이용해 URI에 Enum 타입 매핑하기  (0) 2022.06.26
    'Backend/Spring Boot' 카테고리의 다른 글
    • [API 고급] 컬렉션 조회 최적화
    • [API 개발 고급] 지연 로딩과 조회 성능 최적화
    • 도메인 개발 팁 간단 정리
    • RestTemplate
    Zayson
    Zayson
    공부한 내용을 정리하는 공간

    티스토리툴바