# 회원 조회 API

단순 조회기 때문에 데이터를 변경할 필요 없다.\
resources>application.xml>jpa ddl-auto : none으로 하면 테이블 자동 드랍하지 않는다.\
DB의 데이터를 계속해서 쓸 수 있다!

V1 : **memberService findMembers()** => **MemberRepository findAll()**\
&#x20;                                                       select m from Member m : Member 테이블의 모든 데이터 조회‼️\
\=> Member 클래스에 Json 라이브러리 Jackson의 @JsonIgnore을 조회하지 않는 필드에 붙여주면 해당 필드는 조회 시에 제외된다. (API마다 다르기 때문에 특정 API 설계할 때에 이 API에 맞게 엔티티를 직접 수정하는 것은 매우 안 좋은 방법)

```java
//회원 조회 첫번째 버전 엔티티 노출
@GetMapping("/api/v1/members")
public List<Member> membersV1(){//json으로 변환, 반환
    return memberService.findMembers();
}
```

문제점 : 응답 값으로 엔티티를 직접 외부에 노출

* **엔티티에 프레젠테이션 계층(화면 구성)을 위한 로직이 추가**된다.
* **기본적으로 엔티티의 모든 값이 노출**된다.
* **응답 스펙을 맞추기 위해 로직이 추가**된다. (@JsonIgnore, 별도의 뷰 로직 등등)
* **실무에서는 같은 엔티티에 대해 API가 용도에 따라 다양하게 만들어지는데, 한 엔티티에 각각의 API를 위한 프레젠테이션 응답 로직을 담기는 어렵다.**
* **엔티티가 변경되면 API 스펙이 변한다. (장애 원인, 매우 중요‼️)**\
  **엔티티 필드를 name->username으로 수정하면 엔티티를 직접 반환하기 때문에 name으로 반환되던 것이 매핑이 되지 않는다!**
* 추가로 **컬렉션을 직접 반환**하면 **항후 API 스펙을 변경하기 어렵**다.(**별도의 Result 클래스 생성**으로 해결)\
  **별도의 클래스를 생성하면 컬렉션 필드 뿐만 아니라 추가사항 같은 것들도 쉽게 확장 가능하고, API 스펙 변경 불필요하다!(실무에서 반드시 변경 요구사항이 존재할 수 있다! 그러면 유연성 있게 확장성 좋게 변경이 가능해야한다‼️)**

V2 : 회원 조회 API 역시 DTO를 생성해서 Update 요청과 응답에 이용한다!

```java
@GetMappingg("/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);
}
```

아래 코드처럼 합쳐도 된다.

```java
@GetMappingg("/api/v2/members")
public Result membersV2() {
    //엔티티 -> DTO 변환
    List<MemberDto> collect = memberService.findMembers().stream()
                  .map(m -> new MemberDto(m.getName()))
                  .collect(Collectors.toList());
          return new Result(collect);
}
```

별도의 클래스를 생성해서 리스트 반환 타입을 오브젝트(객체) 타입으로 바꿔서 반환한다‼️\
오브젝트(Result) 타입으로 반환하기 때문에 한번 껍데기를 씌우고 데이터 필드의 값은 리스트가 나간다!

```
 @Data
 @AllArgsConstructor
 class Result<T> {
   private T data;
 }
```

**Java8 문법 람다식 표현(컬렉션 foreach문)**

List.stream().map(변수 -> 엔티티로 만들 객체).collect(Collectors.toList());\
아래 코드 예시 설명\
1\. List\<OrderQueryDTO> 컬렉션에서 각 객체를 변수 o로 받고, 각 객체(OrderQueryDTO)의 id값들을 조회.\
2 .collect(Collectors.toList()) :  리스트로 받는다!

```
List<OrderQueryDTO> result = findOrders();
List<Long> orderIds = result.stream()
                .map(o -> o.getOrderId())
                .colleect(Colleectors.toList());
```

Postman 확인\
GET /api/v2/members

**정리**

* API 설계, 개발 시에는 절대 절대 절대 절대로 엔티티를 직접 사용하거나 반환하면 안 된다!
* 필요한 데이터만 DTO로 만들어서 사용!
* API 스펙과 DTO가 일대일로 매칭되기 때문에 유지보수도 편리하다.
* 엔티티 변경되도 API 스펙 변하지 않는다.
* 컬렉션 타입의 경우, 오브젝트로 한번 감싸기 때문에 변경/추가사항이 생겨도 해당 오브젝트에 변경/추가하면 되기 때문에 확정성, 유연성이 매우 좋다!
