본문 바로가기

Spring Boot

RESTful API 기본 : @RestController

@RestController 애너테이션

 

@RestController = @Controller + @ResponseBody

@Controller는 요청에 대해 HTML View 템플릿을 반환하는데 사용된다.

RESTful한 API 개발에선 JSON, XML, 파일 등 실제 데이터 자체를 반환해야하므로 @RestController가 사용된다.

 - @RestController는 클래스 단위에 적용되며, 내부 모든 메서드는 @ResponseBody의 효과를 가진다.

 - ViewResolver를 거치지 않고 HttpMessageConverter를 통해 응답 데이터로 직렬화된다.

 - 기본 출력 형식은 application/json이며 Accept 헤더로 명시할 수 있다.

@RestController
public class UserController {
	
    @GetMapping("/hello")
    public String hello() {
    	return "Hello JSON!"; // View 형태가 아닌 HTTP 본문에 그대로 출력된다
    }
}

 

@Controller는 View 템플릿이며 사용할 때 @ResponseBody가 필요하다. RESTful API에 적합하지 않다.

@RestController는 HTTP 본문 데이터에 응답하며 JSON으로 자동 반환된다. RESTful API에 적합하다.

 

디렉터리 구조 예

src/main/java/com/example/controller/view/PageController.java - > @Controller 사용함 (Thymeleaf 등..)

src/main/java/com/example/controller/api/UserRestController.java - > @RestController 사용함 (JSON API)

 

 

ResponseEntity를 통한 응답 제어

구조, 목적

ResponseEntity<T>는 HTTP 응답의 전체 구조(상태코드, 헤더, 바디)를 개발자가 직접 제어할 수 있도록 도와주는

스프링 클래스이다.

<T> : 응답 본문에 포함할 객체(JSON으로 직렬화됨)

상태코드 설정 : .ok(), status(HttpStatus.CREATED) 등등..

커스텀 헤더 설정 : .header("key","value") 등..

@RestController
public class UserController {
	
    private final UserService userService;
    
	@PostMapping("/api/users")
    public ResponseEntity<UserDto> create(@ResponseBody CreateUserDto dto) {
    	UserDto saved = userService.create(dto);
        URI location = URI.create("/api/users/" + saved.getId());
        
        return ResponseEntity.created(location) // 201 상태코드 + location 헤더
                             .header("request-ID", UUID.randomUUID().toString())
                             .body(saved); // body는 응답 본문임
    }
}

 

응답코드 예시 (과제에서는 .ok()만 쓴다)

생성 성공 201 Created Location 헤더가 필수임
삭제 성공 204 No Content 본문 없이 성공함(void)
조건 실패 422 Unprocessable Entity 비즈니스 로직 위반, 사용자 문제
서버 오류 500 Internal Server Error 예외 발생, 개발자쪽 문제

 

 

아래는 에러처리에 활용

@GetMapping("/users/{id}")
public ResponseEntity<?> find(@PathVariable Long id) {
	return userService.findById(id) // id를 기반으로 유저를 찾는데
                      .map(ResponseEntity::ok) // ResponseEntity타입을 ok로 반환
                      .orElse(ResponseEntity.status(HttpStatus.NOT_FOUND) // 할수없다면 예외발생
                                            .body(Map.of("error","사용자를 찾을 수 없음")));
}

 

* 성공 응답은 200, 201, 204로 구분하고 실패응답은 400, 401, 403, 404, 422등 정확하게 설계해야한다.

* Swagger 문서에서도 상태코드별 응답형식을 명시하면 클라이언트 개발자와 협업을 했을 때 충돌이 줄어든다.

* ResponseEntity<Object>는 왠만하면 피하고 제네릭 타입을 명시해야한다. 타입 안정성과 직렬화 성능 향상에 유리하다.

 

 

 

HTTP 메세지 컨버터(MessageConverter)의 동작방식

메세지 컨버터 : Spring에서 요청 본문을 자바 객체로 변환하거나, 자바 객체를 응답 본문으로 직렬화할 때 사용하는 컴포넌트

 

요청흐름

HTTP JSON 요청 - > HttpMessageConverter - > @RequestBody - > Java 객체

 

응답흐름

Java 객체 - > @ResponseBody or ResponseEntity - > HttpMessageConverter - > HTTP 응답 JSON

 

 

Spring 내장 컨버터(자세하게 알 필요까진 없다)

클래스 기능 미디어 타입
MappingJackson2HttpMessageConverter JSON - > 객체 application/json
StringHttpMessageConverter 문자열 변환 text/plain
ByteArrayHttpMessageConverter 바이너리 파일 처리 application/octet-stream
FormHttpMessageConverter application/x-www-form-urlencoded 폼 데이터 처리

* spring-boot-starter-web을 사용하면 Jackson 기반 JSON 컨버터가 자동으로 설정된다.

 

 

Content Negotiation(콘텐츠 협상)

클라이언트의 Accept 헤더에 따라 반환 형식을 결정한다.

Accept: application/json - > JSON 응답

Accept: application/xml - > XML 응답

@PostMapping(value = "/data",
              produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public DataDto getData() {
	return new DataDto();
}

produces 안에 있는 MediaType이 중요한것 같은데.. 아니면 value값에 따라 반환 형식이 결정되는건가?

* XML 컨버터 사용시 jackson-dataformat-xml을 추가해줘야한다.

 

커스텀 컨버터 : 어려우니 다음 시간에

* 파일 업로드는 MultipartHttpServletRequest, @RequestPart와 multipart/form-data 컨버터의 조합으로 한다고 한다.

 

아~

자주 쓰는 핵심 애너테이션인데 어렵네요잉

'Spring Boot' 카테고리의 다른 글

Entity 설계  (7) 2025.07.22
RESTful 구현 기본 : Controller에서 요청 처리  (1) 2025.07.18
REST : 제약조건  (0) 2025.07.10
REST : 탄생배경과 개념  (7) 2025.07.10
MVC : Spring Boot 시작하기  (0) 2025.07.06