Network/2. HTTP

Spring RESTful API 특징

snowkit 2022. 2. 22. 13:44

일반

  • Spring Framework는 Jackson 라이브러리를 통해 값을 매핑한다.
  • Spring Framework는 HTTP Body와 URL 쿼리스트링에 들어있는 값을 받는다.
    • HTTP Method, Content-Type, 파라미터 어노테이션(@RequestParam, @ModelAttribute, @RequestBody)에 따라 받는 값이 다르다.
  • HTTP Body와 URL 쿼리스트링 값을 동시에 받는 상황에서 key가 중복되는 경우
    • 파라미터 데이터 타입이 String이 아니라면 하나의 값만 받는데, HTTP Body 값을 우선으로 받는다.
    • 파라미터 데이터 타입이 String이라면 컴마(,)로 구분하여 모든 값을 받는다.
    • 파라미터 데이터 타입이 배열이나 Collection이라면 모든 값을 받는다.
  • GET
  application/x-www-form-urlencoded multipart/form-data application/json
@RequestParam Query String 값만 받음
HTTP Body 값 무시
Query String, HTTP Body 값 중복으로 받음 Query String 값만 받음
HTTP Body 값 무시
@ModelAttribute Query String 값만 받음
HTTP Body 값 무시
Query String, HTTP Body 값 중복으로 받음 Query String 값만 받음
HTTP Body 값 무시
@RequestBody Query String 값 무시
HTTP Body 값만 받음
Query String, HTTP Body 값  전부 무시 Query String 값 무시
HTTP Body 값만 받음
  • GET을 제외한 Method
  application/x-www-form-urlencoded multipart/form-data application/json
@RequestParam Query String, HTTP Body 값 중복으로 받음 Query String, HTTP Body 값 중복으로 받음 Query String 값만 받음
HTTP Body 값 무시
@ModelAttribute Query String, HTTP Body 둘 중 하나의 값만 받음 (Query String 값 우선) Query String, HTTP Body 값 중복으로 받음 Query String 값만 받음
HTTP Body 값 무시
@RequestBody Query String 값, HTTP Body 값 전부 받음 Query String, HTTP Body 값  전부 무시 Query String 값 무시
HTTP Body 값만 받음

 

Annotation

  • 파라미터 앞에 사용하는 어노테이션으로, 데이터 타입에 따라 구분한다.

@RequestParam

  • 하나의 key에 해당하는 값을 받을 때 사용한다.
  • Spring에서 정한 "간단한 타입"에 대해서 사용 가능하다.
    • 구글에 검색해보면 String, int, long 등 String과 primitive 타입만 적용되는 것처럼 알려져 있으나 정확한 목록은 다음과 같다. (BeanUtils.isSimpleValueType 메소드에서 확인 가능)
    • 간단한 타입 목록
      • Primitive 타입 (boolean, byte, char, short, int, long, float, double)
      • Primitive Wrapper 타입 (Boolean, Byte, Character, Short, Integer, Long, Float, Double, Void)
      • Enum
      • CharSequence
      • Number
      • Date
      • Temporal
      • URI
      • URL
      • Locale
      • Class
  • 어노테이션 생략 가능
    • 생략 시 자동으로 @RequestParam(required = false)가 붙은 것과 마찬가지로 동작한다. 실제로 없는 어노테이션이 자동으로 생성되는 건 아니고 RequestParamMethodArgumentResolver.RequestParamNamedValueInfo 클래스에서 다음과 같이 동작한다.
      // 어노테이션이 없는 경우 호출하는 생성자
      public RequestParamNamedValueInfo() {
          super("", false, ValueConstants.DEFAULT_NONE);
      }
      
      // 어노테이션이 있는 경우 호출하는 생성자
      public RequestParamNamedValueInfo(RequestParam annotation) {
          super(annotation.name(), annotation.required(), annotation.defaultValue());
      }​
  • 어노테이션을 생략하지 않는 경우 required 값을 필요에 따라 false로 바꾸거나 defaultValue를 설정해서 사용할 수 있다.
  • 여러 key 값들을 Map으로 받고 map.get("key")로 값을 가져올 수도 있지만 좋은 코드는 아니기 때문에 거의 사용되지 않는다.
    • 이렇게 사용하는 경우 파라미터(Map)에 선언한 제네릭은 무시되고 key와 value 전부 String으로 저장된다.
    • DTO 대신 Map을 사용하면 안에 어떤 key가 들어있는지 알기 힘들다.

@ModelAttribute

  • 일반적으로 여러 key 값을 객체에 받을 때(Ex. DTO) 사용한다.
    • key와 객체의 필드명은 일치해야 한다.
    • Setter를 통해 값을 객체에 바인딩하기 때문에 Setter를 생성해야 한다.
  • Spring에서 정한 "간단한 타입" 이외의 데이터 타입에 대해서 사용 가능하다.
  • 어노테이션 생략 가능
    • 생략 시 자동으로 @ModelAttribute가 붙은 것과 마찬가지로 동작한다.
    • ModelAttributeMethodProcessor.supportsParameter 메소드에서 확인할 수 있으며 조건은 다음과 같다.
      public boolean supportsParameter(MethodParameter parameter) {
          return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
                  (this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
      	// 어노테이션이 있는 경우 || (어노테이션이 필수가 아니고 "간단한 타입"이 아닌 경우)
      }

@RequestBody

  • HTTP Body를 그대로 가져오며 일반적으로 JSON 데이터를 받을 때 사용한다.
  • 여러 key 값을 객체(DTO)에 받을 수 있다.
    • key와 객체의 필드명은 일치해야 한다.
    • Jackson에서 리플렉션을 통해 값을 바인딩하는데, 필드를 찾기 위해 Getter나 Setter 둘 중 하나는 반드시 생성해야 한다.
      • status라는 필드가 있다면, getStatus()나 setStatus() 메소드 중 하나를 찾아 앞의 get과 set을 제외하고 첫 문자를 소문자로 바꿔서 필드를 찾아 값을 저장한다.
    • 객체에 값을 받는 경우 HTTP Content-Type이 application/json이 아니라면 Exception이 발생한다.
  • String으로 HTTP Body 문자열을 그대로 받을 수 있다.
    • String으로 값을 받는 경우 HTTP Content-Type이 제한되지 않는다.

Content-Type

  • REST API 요청의 Content-Type은 대부분 다음 셋 중 하나로 들어온다.
    • application/x-www-form-urlencoded
    • multipart/form-data
    • application/json

application/x-www-form-urlencoded

  • 일반적으로 @RequestParam 또는 @ModelAttribute와 함께 사용해 Controller에서 값을 받는다.
    • 메소드가 GET인 경우 HTTP Body에 값을 담을 수 없기 때문에 클라이언트에서 URL 쿼리스트링에 값을 담아 요청해야 한다.
    • 메소드가 GET이 아닌 경우 HTTP Body에 값을 담아서 보낼 수 있다.
  • @RequestBody를 사용하면 HTTP Body 값을 받을 수 있다.

multipart/form-data

  • 일반적으로 @RequestParam 또는 @ModelAttribute와 함께 사용해 Controller에서 값을 받는다.
    • 모든 메소드에서 HTTP Body에 값을 담아 보낼 수 있다.
  • 파일을 전송할 때 사용한다.
    • Spring 설정을 통해 일정 크기가 넘어가는 파일은 메모리가 아닌 파일시스템에 임시로 저장해서 사용할 수 있다.
  • @RequestBody를 사용하면 아무 값도 받을 수 없다.

application/json

  • 일반적으로 @RequestBody와 함께 사용해 Controller에서 값을 받는다.
    • 모든 메소드에서 HTTP Body 값을 받을 수 있다.
    • REST API에서 가장 많이 사용하는 타입이다.

'Network > 2. HTTP' 카테고리의 다른 글

RESTful API 설계  (0) 2022.02.22