카테고리 없음

Spring Boot - API

팅탱팅탱 2024. 4. 1. 18:00

회원 등록 API

api는 따로 디렉토리로 빼서 작업을 해주는게 좋다고 합니다.

 

우선 api를 만드는 2가지 방법중 첫번째 방법으로 해보겠습니다.

api를 개발하기전 rescontroller 어노테이션을 추가해줍니다.

@RestController // =  @Controller + @ResponseBody

 

 

 

회원 등록이니 api의 post url을 지정해주고 파라미터로 멤버 객체를 받아서 회원가입을 시켜주는것을 구현하였습니다.

@requestbody는 json으로 온 데이터를 member에 매핑해줍니다.

(Member 클래스에서는 name의 값을 필수적으로 받기위해서 NotEmpty 어노테이션을 사용)

 

응답값은 CreateMemberResponse를 만들어주어서 회원등록이 되면 id값을 반환할 수 있도록 만들었습니다.

 

포스트맨으로 확인결과 응답값과 통신 모두 잘 되었습니다.

 

하지만 이렇게 구현할시에 심각한 문제가 많습니다.

단순 등록인데 아까 멤버 객체에 이름값을 필수적으로 받기 위해서 NotEmpty 어노테이션을 사용하였다고 말씀드렸습니다.

그 경우 사용자가 직접 값을 입력하는 presentation 계층을 위한 검증 로직이 객체에 구현이 되어있는 것입니다.

즉 다른말로 어떤 api에서는 NotEmpty가 필요할 수도 있겠지만 어떤 api에서는 필요가 없다는 것을 의미합니다.

다음으로는 객체의 스펙을 name에서 username으로 변경할시에 api 스펙 자체가 변경이 되어버립니다.

문제는 객체를 손대서 api 스펙 자체가 변하는 것이 문제입니다.

객체는 굉장히 여러곳에서 쓰이는 것입니다. (바뀔 확률이 매우 높음)

(객체랑 api 스펙이 1대1로 매핑이 딱 되어있다는 뜻입니다)

따라서 이런 경우를 방지하기 위해서 api 스펙을 위한 별도의 데이터 트렌스퍼 오브젝트(DTO)를 만들어야합니다.(별도의 DTO를 파라미터로 받는게 좋습니다)

엔티티를 외부에서 json오는것을 바인딩 받는데 사용하는것은 안됩니다.(장애가 발생 할 수 있음)

api를 만들때는 항상 파라미터로 객체를 받지않기!(객체를 외부에 노출해서도 안됨)

 

이걸 적용한 2번째 방법으로 해보겠습니다.

바로 객체를 파라미터로 받지않고 CreateMemberRequest DTO를 생성하여서 DTO를 파라미터로 넣어줌으로써 구현하였습니다.

반환값이 잘 나오는게 확인됩니다.

이렇게 구현할시에 장점은 api의 스펙이 변하지 않게되고, 서비스를 안정적으로 운용 할 수 있게됩니다.

또한 지금 멤버는 파라미터가 어떤것이 넘어올지 모르는데 (id,name,address,orders등) DTO를 만들어놓으면 api 스펙자체에서 어떤 값을 받는지 바로 알 수 있습니다.

validation을 하고싶으면

NotEmpty 어노테이션을 DTO에 추가하여서 구현 가능합니다.

 

회원 수정 API

회원 수정을 위해서는 putmapping을 사용해주어서 경로변수로 id값을 받아서 수정해주도록 구현하였습니다.

구현시 아까와 같이 객체를 파라미터로 넘겨주는것이 아닌 수정 DTO를 생성하여서 파라미터로 넘겨주었습니다.

@AllArgsConstructor 어노테이션을 사용해주었기에 따로 생성자는 만들지 않았습니다.

회원 이름 수정시에 update 함수를 사용하여 변경감지를 통하여 영속상태인걸 이용하여서 트렌젝션이 커밋시에 JPA가 데이터를 추적해서 변경감지를 할 수 있게 함수를 구현 하였습니다.

MemberService class

다음으로 멤버를 id로 찾아준뒤 변경된 멤버의 id,name값을 리턴해주었습니다.

 

멤버를 생성해주고 해당 id 값으로 이름 수정을 하니 리턴값에 이름 변경이 제대로된걸 알 수 있습니다.

 

회원 조회 API

지금까지는 단순 조회이기때문에 yml 파일에있는 auto-ddl을 none으로 설정해줍니다.(데이터를 계속 쓸수있게됨)

회원 조회시에는 그냥 회원 정보들을 다 list로 뽑아주면됩니다.

그 결과 회원들의 정보들이 list로 나오게되는데 이때 회원들의 정보만 추출하려했지 order은 추출하려하지않음

이때 @JsonIgnore 어노테이션을 사용하여서 order값을 추출값에서 빼줄수있습니다.

하지만 이렇게 구현할시 다른 api 개발을 함에 있어서 어떤 api는 order도 필요하고 어떤 api에서는 회원 정보 + order이 다 필요한 경우가 있을수 있기때문에 이런식의 개발은 좋지않습니다.

 

응답값으로 엔티티를 위처럼 직접 외부에 노출하게된다면

1. 엔티티(객체)에 프레젠테이션 계층의 로직이 추가된다.

2. 기본적으로 엔티티의 모든 값들이 외부에 노출된다.

3. 응답 스펙을 맞추기 위하여 로직들이 추가된다.(@JsonIgnore 등등)

4. 실무에서는 같은 엔티티에 대하여 api가 용도에 따라 다양하게 만들어지는데 한 엔티티에 각각의 api를 위한 프레젠테이션 응답 로직을 담기는 어렵다.

5.  엔티티가 변경되면 api 스펙이 변한다.

 

파훼법

1. api 응답 스펙에 맞추어 별도의 DTO를 구현한다.

 

단점들을 보완하여 다시 구현해보겠습니다.

 

회원정보중 간단하게 이름만 추출할수있도록 DTO를 구현하였으며 []:array의 형태로 감싸진 데이터(추후 추가 데이터를 넣으려면 json 형식이 파괴되어서 매우 복잡해짐)가 아닌 형태로 추출하기 위하여 구현해주었습니다.

다음으로 리스트를 추출하는건 동일하지만 아까 구현해놨던 멤버DTO로 추출한 리스트를 매핑 시켜주어서 구현하였습니다.

또한 추가로 count(추출된 데이터의 갯수)라는 정보를 바로 추가할수있게끔([]형태로 안해서 가능한 구현)확인하기 위하여 추출값을 넣어주었습니다.