![[스프링부트 #20] REST API 설계의 핵심](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog-custom%3Ftitle%3D%255B%25EC%258A%25A4%25ED%2594%2584%25EB%25A7%2581%25EB%25B6%2580%25ED%258A%25B8%2B%252320%255D%2BREST%2BAPI%2B%25EC%2584%25A4%25EA%25B3%2584%25EC%259D%2598%2B%25ED%2595%25B5%25EC%258B%25AC%26tag%3DTemplate%2B1%26description%3D%26template%3D3%26backgroundImage%3Dhttps%253A%252F%252Fsource.inblog.dev%252Fog_image%252Fdefault.png%26bgStartColor%3D%252323ec86%26bgEndColor%3D%252323ec86%26textColor%3D%2523000000%26tagColor%3D%2523000000%26descriptionColor%3D%2523000000%26logoUrl%3D%26blogTitle%3DGyeongwon%2527s%2Bblog&w=2048&q=75)
1. DTO와 엔티티는 분리해야한다.
@RequestBody
: JSON 데이터를 자바 객체로 변환해 받는다. insert, update 시에는 해당 행을 리턴받아 DTO로 변환해 응답하는 것이 좋다. DTO는 Entity를 받아 생성자에서 필요한 데이터만 추출한다.민감 정보(예: 비밀번호)는 반드시 제외한다.
@Data
public class UserDTO {
private Integer id;
private String username;
private String email;
public UserDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
}
}
엔티티를 그대로 응답하면 양방향 매핑 때문에 JSON 직렬화 시 무한 참조 문제가 발생할 수 있으므로 반드시 DTO로 변환한다.
2. 객체지향 원칙 - 상태 변경은 행위를 통해
상태(필드)는
private
로 두고, 메서드를 통해서만 변경해야 한다. 여러 객체가 상태를 가질 경우 메서드 호출로 통신해야 한다. 유지보수 시 의존성을 줄이기 위해 화면별로 필요한 필드만 갖춘 DTO를 정확히 설계해야 한다. 3. 예외 처리 - GlobalExceptionHandler
API 에러 응답은 하나의 통일된 DTO 포맷으로 내려준다. HTTP 상태코드와 메시지를 함께 반환한다.
ResponseEntity
를 사용해 바디와 상태코드를 명시적으로 작성한다.나는 200, 400, 401, 403, 404, 500 등 주요 상태코드별 커스텀 예위 클래스를 설계하였다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception400.class)
public ResponseEntity badRequest(Exception400 e) {
return new ResponseEntity(Resp.fail(400, e.getMessage()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception401.class)
public ResponseEntity unAuthorized(Exception401 e) {
return new ResponseEntity(Resp.fail(401, e.getMessage()), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(Exception403.class)
public ResponseEntity forbidden(Exception403 e) {
return new ResponseEntity(Resp.fail(403, e.getMessage()), HttpStatus.FORBIDDEN);
}
@ExceptionHandler(Exception404.class)
public ResponseEntity notFound(Exception404 e) {
return new ResponseEntity(Resp.fail(404, e.getMessage()), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception500.class)
public ResponseEntity serverError(Exception500 e) {
return new ResponseEntity(Resp.fail(500, e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(Exception.class)
public ResponseEntity unknown(Exception e) {
System.out.println("로그 기록: " + e.getMessage());
return new ResponseEntity(Resp.fail(500, "관리자에게 문의하세요"), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
4. REST API 설계 포인트
- URL은 자원 중심 (
/api/boards/5
) → 복수형 사용 권장한다.
Content-Type
에서 MimeType 지정 중요 →application/json
- REST API는 프로토콜(규칙)이며, 약속을 팀 내에서 합의하고 일관성 있게 적용한다.
- 처음에는 DTO를 넉넉히 만들고 필요 데이터만 꺼내 쓰는 방식도 괜찮지만, 유지보수성을 위해 정확한 DTO 설계가 필수이다.
요약
- DTO는 엔티티와 분리하고, 민감정보는 제외하고,
- 상태 변경은 반드시 메서드를 통해서 한다.
- 에러 응답 포맷과 상태코드 표준화한다.
- REST API URL과 응답 구조 일관성 유지해야 한다.
- JSON 직렬화 시 무한 참조 방지를 위해 엔티티 직접 반환 지양하고, DTO 사용한다.
Share article