package jpabook.jpashop.api;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.service.MemberService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
@RequiredArgsConstructor
public class MemberApiController {
private final MemberService memberService;
@PostMapping("/api/v1/members")
public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){
Long id = memberService.join(member);
return new CreateMemberResponse(id);
}
@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{
private String name;
}
@Data
static class CreateMemberResponse{
private Long id;
public CreateMemberResponse(Long id) {
this.id = id;
}
}
}
📌 [포스트맨415에러]_@RequestBody를 지워야하는 이유
혹은 Header에서 Content-Type를 application/json로 수정
실무에서는 엔티티를 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
static class UpdateMemberResponse {
private Long id;
private String name;
}
public memberService{
...
@Transactional
public void update(Long id, String name) {
Member member = memberRepository.findOne(id);
member.setName(name);
}
}
@GetMapping("/api/v1/members")
public List<Member> membersV1(){
return memberService.findMembers();
}
@Entity
@Getter @Setter
public class Member {
@Id @GeneratedValue
@Column(name="member_id")
private Long id;
@NotEmpty
private String name;
@Embedded
private Address address;
@JsonIgnore
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
단점: Enitity가 그대로 노출이 됨.
@JsonIgnore
사용 시, postman으로 api를 이용한 서버 응답을 받았을 때 특정 데이터를 노출이 안되게 변경 가능
📌 API 응답 스펙에 맞추어 별도의 DTO를 반환하여 필요한 것만 노출
@GetMapping("/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);
}
@Data
@AllArgsConstructor
static class Result<T>{
private T data;
}
@Data
@AllArgsConstructor
static class MemberDto{
private String name;
}