Spring을 이용한 API 개발, 기본

Yebali·2021년 4월 18일
0

약간의_Spring

목록 보기
12/30
post-thumbnail

Spring을 이용해 API를 개발할 때, 참고하면 좋을 수 있는 글.

예시에서는 Member라는 Entity를 사용한다.

  @Data
  @Entity
  public class Member {

      @Id @GeneratedValue
      @Column(name = "member_id")
      private Long id;

      private String name;

      @Embedded
      private Address address;

      @JsonIgnore 
      @OneToMany(mappedBy = "member")
      private List<Order> order = new ArrayList<>();
  }

등록(Post) API

  @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 {
      @NotEmpty
      private String name;
  }

요청 파라미터를 'Member' Entity에 직접 매핑하지 않고, 임의의 DTO(CreateMemberRequest)에 매핑한다.
Entity와 API스펙을 명확히 분리 할 수 있으며 Entity가 변해도 API스팩은 변하지 않는다.

수정(Post/Put) API

  @PutMapping("/api/v2/members/{id}")
  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());
  }

  @Data
  static class UpdateMemberRequest {
      private String name;
  }

  @Data
  @AllArgsConstructor
  class UpdateMemberResponse {
      private Long id;
      private String name;
  }

등록 API와 마찬가지로 임의의 DTO(UpdateMemberResponse)에 요청 파라미터를 매핑하는 것이 좋다.

전체를 업데이트 할 때에는 PUT을 사용하고,
부분 업데이트를 할 때에는 PATCH나 POST를 사용하는 것이 REST 스타일에 맞다.

조회(Get) API

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
 class Result<T> {
 	private int count;
 	private T data;
 }
 
 @Data
 @AllArgsConstructor
 class MemberDto {
 	private String name;
 }

조회에서도 Entity를 직접 반환하는 것이 아닌 DTO로 변환해서 반환한다.

API개발에서 Entity를 직접 사용했을 때 문제

  1. Entity에 API 검증 로직이 추가되어야 한다. (ex. @NotEmpty)
  2. 실무에서는 Entity를 위한 다양한 API가 만들어지는데, 하나의 Entity에 모든 API의 요구사항들을 반영하기는 어렵다.
  3. Entity가 변경되면 API 스펙이 변한다.

기본적으로 실무에서는 Entity를 API스펙이 노출하면 안된다!
Entity <-> DTO <-> View(Client) 의 형태로 통신할 수 있도록 하자.

조회에서 굳이 Result 클래스를 만든 이유?

추가로 API를 위해 만든 컬랙션을 직접 반환하면 향후 API스팩을 변경하기 어렵다.
이런 경우 별도의 Result 클래스를 만들어 해당 클래스를 반환하도록 해주면 좋다.

    @Data
    @AllArgsConstructor
    static class Result<T> {
        private int count; // API에서 추가적으로 원하는 정보
        private T data;  //반환 할 데이터
    }

이렇게 별도의 Result 클래스를 만들면 응답을 확장 할 수 있는 유연성이 증가한다.
추가 정보가 필요하면 멤버 변수만 추가하면 끝.


Result 클래스를 사용한 반환 결과 예시.

출처: https://www.inflearn.com/users/@yh

profile
머리에 다 안들어가서 글로 적는 중

0개의 댓글