일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 코테준비
- AtoZ0403
- mybatis
- stack
- 콜백지옥
- 인프런
- js
- 정렬
- 알고리즘
- javascript
- spring
- java
- 자바
- 자바스크립트
- 중간 평균값 구하기
- NestJS
- SWEA
- 코테
- 프로그래머스
- 그리디알고리즘
- 삼성
- 코딩
- array
- 배열
- 백준
- 카카오
- 코딩테스트
- 자료구조
- 스텍
- 삼성소프트웨어아카데미
- Today
- Total
개발에 AtoZ까지
[SpringBoot] HTTP Status Code 제어 중요성 및 방법 본문
◆목표
HTTP Status Code란
HTTP Status Code의 중요성
HTTP Status Code 제어 및 Spring 예외처리 방법(SpringBoot)
SpringBoot에서 적용방법
1. HTTP Status Code란?
HTTP Status Code(HTTP 상태 코드)는 클라이언트가 보낸 HTTP 요청에 대한 서버의 응답을 코드로 표현한 것으로 해당 코드로 요청의 성공 / 실패 / 실패요인
등을 알 수 있다.
2. HTTP Status Code의 중요성
아래와 같이 URI에 USERS/ID 입력하고 GET 메소드로 조회하는 스프링 예제가 있다.
아래 예제는 Users에 ID값이 1~3까지 밖에 없는 상황에서 ID값이 100인 사용자를 조회한 결과이다.
호출 시 분명 없는 사용자를 조회했으니 없다는 내용 또는 에러가 반환해야 할 것 같지만, 결과는 그렇지 않다. 왜냐하면 HTTP 입장에서는 해당 URI 호출이 문법적으로 오류가 없고 정상적으로 서버에서 응답
을 줬기 때문에 HTTP 상태코드는 200
인 것이다.
이런 경우는 REST API 설계 시 올바르지 않은 설계 중 하나다.
왜냐하면 직관적이지 않고 명확하지 않기 때문이다. 그러면 어떻게 올바르게 수정할 수 있을까?
아래와 같이 HTTP 상태코드를 변경하여 응답해주는것이 좋은 방법이라고 생각한다.
추가적으로 POST인 경우도 살펴보겠다.
아래 예제는 User Create하는 API를 POST 메소드로 호출하는 예제이다.
HTTP 상태코드를 보았을 때 200으로 성공이라는 뜻을 가지고 있지만 명확하지는 않다고 생각한다.
그래서 실제 클라이언트가 요청한 Create 작업이 정상적으로 됐는지 더 직관적으로 알 수 있도록 해주는 것이 좋을 것 같다.
적용을 하게 되면 아래와 같이 HTTP 상태코드를 201 Create로 변경하여 응답하는것이 더 좋은 방법이라고 생각한다.
3. HTTP Status Code 제어 및 Spring 예외처리 방법(SpringBoot)
스프링 부트 환경에서 예외처리에 따른 HTTP 상태 코드를 관리하는 방법은 2가지 정도가 있을 것 같다.
첫 번째, 각각의 상황에 따라 Exception Class을 만들어서 해당 클래스에서 관리하는 방법
두 번째, 첫 번째 방법에서 만든 Exception Class를 가지고 중앙에서 관리하는 방법
첫 번째와 두 번째를 비교했을때 가장 큰 차이점은 Exception 관리를 한곳에서 할 수 있냐 없냐는 차이 일것이다.
조금 더 쉽게 설명해보자면 두번째 방법에서 "중앙에서 관리한다"라는 말은 SpringBoot에서 지원하는 @controllerAdvice 어노테이션을 사용해 Exception 발생 시 해당 어노테이션이 있는 클래스에서 예외처리를 해줄 수가 있다.
한두 개의 Exception class가 있다면 상관없지만 다수의 Exception Class를 관리하거나 유지 보수하려고 한다면 두 번째 방법을 사용하는 것이 좋을 것이다.
그럼 실제 예제 코드를 보면서 확인해보겠다.
먼저 첫 번째 방법의 코드이다.
@GetMapping("/users/{id}")
public User retrieveUser(@PathVariable int id){
User user = service.findOne(id);
if(user==null){
throw new UserNotFoundException(String.format("%s not found",id));
}
return user;
}
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message){
super(message);
}
}
위에서 보는 것과 같이 사용자가 없는 상황일 때 명확하게 HTTPSTATUS.NOT_FOUND(404) 로 반환하여 프론트개발자 또는 클라이언트에게 명확하게 반환하는 것이 명시적이고 좋은 REST API 설계라고 생각한다. 그런데 만약 이런 Exception Class들이 엄청 많아진다면 어떻게 관리하면 좋을까? 그 방법이 두번째 방법이라고 생각한다.
두 번째 예제코드이다.
package com.ksh.restfulapiexam.Exceptions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.Date;
@RestController
@ControllerAdvice
public class customizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
//Default exception
@ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request){
ExceptionResponse exceptionResponse = new ExceptionResponse().builder()
.timestamp(new Date())
.message(ex.getMessage())
.details(request.getDescription(false))
.build();
return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(UserNotFoundException.class)
public final ResponseEntity<Object> handleUserNotFoundExceptions(Exception ex, WebRequest request){
ExceptionResponse exceptionResponse = new ExceptionResponse().builder()
.timestamp(new Date())
.message(ex.getMessage())
.details(request.getDescription(false))
.build();
return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
}
}
두 번째 방법을 봤을 때 @ControllerAdvice 어노테이션으로 구성된 Class만 보더라고 이 프로젝트에서 어떤 예외처리를 하고 있는지 한눈에 볼 수 있다는 점에서도 좋은 설계라고 생각한다.
📌기재한 내용 중 잘못된 내용이나 보충설명이 필요한 부분이 있다면 주저하지 마시고 피드백 부탁드리겠습니다.🙏
'백엔드 > REST API' 카테고리의 다른 글
[HTTP통신] HTTP 메소드 및 특징 (0) | 2021.06.06 |
---|---|
[네트워크][통신방식] Socket 통신과 Http 통신의 비교 (0) | 2021.03.03 |
[개념] REST, REST API, RESTful 정의 및 특징 (0) | 2021.02.14 |