Spring

SpringBoot | ResponseEntity란?

이진유진 2024. 3. 11. 13:26
반응형

 

회사에서 스프링 시큐리티를 컨트롤하다, 기존 Controller의 리턴값에서 불편함을 느껴 스터디를 진행해보았습니다.

ResponseEntity란? 

Spring Framework에서 HTTP 응답을 나타내는 클래스입니다. 

주로 MVC 컨트롤러에서 클라이언트에게 HTTP 응답을 반환할 때 사용됩니다. 

 

ResponseEntity는 응답의 HTTP 상태 코드, 헤더, 본문(Body) 등을 포함하는데 사용됩니다. 

 

  1. HTTP 상태코드(Status Code) 
  2. HTTP Headers 
    • 헤더는 키-값의 쌍으로 이루어져 있습니다. 
    • 캐시관련 헤더, 컨텐츠 헤더, 인코딩 등이 있습니다. 
  3. 응답 본문(Body)
    • 클라이언트로 전송될 응답의 본문을 나타냅니다. 
    • 주로 JSON, XML, HTML 등의 형식으로 데이터를 포함할 수 있습니다. 

ResponseEntity를 사용하는 이유?

일반적으로 Controller에서 객체를 리턴 시, HTTP 응답을 제어할 수 없습니다. 

@GetMapping("/")
public User getUser() {
    User user = userService.getUser();
    return user;
}

 

그래서, RESTful API 아키텍처를 기반으로 하는 웹 서비스를 설계하고 구현하는 데 사용되는 API 스타일을 적용하는게 좋습니다. 

 


RESTful API란?

HTTP 프로토콜을 기반으로 하며, 자원(Resource)을 URI로 표현하고, HTTP 메서드(GET, POST, PUT, DELETE 등)를 이용하여 해당 리소스에 대한 상호작용을 수행합니다. 

특징

1. 자원(Resource)
  RESTful API에서 모든 것은 리소스로 간주됩니다. 리소스는 개체, 서비스 또는 데이터 등을 나타내며, 각 리소스는 고유한 URI(Uniform Resource Identifier)를 가집니다. 

2. URI(Uniform Resource Identifier)
  각 리소스는 URI를 통해 식별됩니다. URI는 리소스의 위치를 나타내며, 간결하고 직관적으로 디자인되어야 합니다. 

3. HTTP Method 활용 
  HTTP 메서드를 통해 리소스에 대한 특정 동작을 수행합니다. 

4. 표현(Representation)
  리소스의 상태는 표현을 통해 클라이언트에 전달됩니다 일반적으로는 JSON 또는 XML 형식으로 데이터를 표현합니다. 

5. 상태 전이(Stateless)
  RESTful API는 상태를 유지하지 않는 특성을 갖습니다. 각 요청은 모든 필요한 정보를 포함하고 있으며, 서버는 클라이언트의 상태를 저장하지 않습니다. 

6. HATEOAS(Hypermedia As The Engine Of Application State)
  클라이언트가 서버에서 전송된 리소스를 통해 어떤 동작을 수행할 수 있는지 알 수 있도록 하이퍼미디어 링크를 포함합니다. 

7. 캐싱(Caching)
  캐싱은 응답을 클라이언트에서 저장하여 이후 동일한 요청에 대해 다시 전송하지 않고 캐시된 응답을 사용하도록 하는 메커니즘을 의미합니다. 
  HTTP의 기존 웹 표준을 그대로 사용하여, HTTP가 가진 캐싱 기능이 적용 가능합니다. 

8. 계층 구조(Layered System)
  RESTful 서비스는 계층 구조로 설계되어 있어, 각 계층은 다른 계층의 구현 세부사항을 알 필요 없이 독립적으로 개발될 수 있습니다. 

 

ResponseEntity 사용방법

1. 기본적인 사용

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/example")
    public ResponseEntity<String> getExample() {
        String responseBody = "Hello, World!";
        return new ResponseEntity<>(responseBody, HttpStatus.OK);
    }
}

 

2. 헤더와 본문 설정

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class MyController {

    @GetMapping("/example")
    public ResponseEntity<String> getExample() {
        String responseBody = "Hello, World!";
        HttpHeaders headers = new HttpHeaders();
        headers.add("Custom-Header", "Value");

        return new ResponseEntity<>(responseBody, headers, HttpStatus.OK);
    }
}

 

3. 에러 응답 처리 

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/divide")
    public ResponseEntity<String> divideNumbers(
            @RequestParam int dividend,
            @RequestParam int divisor) {
        
        if (divisor == 0) {
            return new ResponseEntity<>("Division by zero is not allowed.", HttpStatus.BAD_REQUEST);
        }

        int result = dividend / divisor;
        return new ResponseEntity<>("Result: " + result, HttpStatus.OK);
    }
}

 

4. 동적으로 상태 코드 설정 

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/dynamic-status")
    public ResponseEntity<String> dynamicStatusExample(@RequestParam boolean success) {
        if (success) {
            return new ResponseEntity<>("Operation succeeded!", HttpStatus.OK);
        } else {
            return new ResponseEntity<>("Operation failed!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

 

5. 다양한 리턴 타입 활용

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/example-object")
    public ResponseEntity<MyObject> getExampleObject() {
        MyObject myObject = new MyObject("Example Data");
        return new ResponseEntity<>(myObject, HttpStatus.OK);
    }

    private static class MyObject {
        private final String data;

        public MyObject(String data) {
            this.data = data;
        }

        public String getData() {
            return data;
        }
    }
}
반응형