[Spring Boot] #19. HTTP와 RestController

gogori6565·2024년 7월 29일
0

스프링 부트 공부

목록 보기
17/20

👉 Mission. 기존 Article 데이터를 CRUD 하기 위한 Rest API를 구현하시오


클라이언트-서버의 비동기 통신

비동기 통신이란, request에 대한 response를 기다리지 않고 계속 request를 보내는 방식이다. 따라서 응답 순서는 요청 순서와 다를 수 있다. 해당 방식은 결과보다는 더 빠른 성능이 요구되는 서비스에 적절하고, 결과가 중요한 서비스에서는 추천하지 않는 방식이다.


클라이언트에서 서버로 통신하는 메시지를 요청(request) 메시지라고 하며, 서버에서 클라이언트로 통신하는 메시지를 응답(response) 메시지라고 한다.
웹에서 화면전환(새로고침) 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어진다.
비동기 통신을 하기위해서는 클라이언트에서 서버로 요청 메세지를 보낼 때, 본문에 데이터를 담아서 보내야 하고, 서버에서 클라이언트로 응답을 보낼때에도 본문에 데이터를 담아서 보내야 한다. 
이 본문이 바로 body 이다.
즉, 요청본문 requestBody, 응답본문 responseBody 을 담아서 보내야 한다.

RequestBody와 ResponseBody는 모두 비동기 처리 방식이다. 두 어노테이션은 모두 웹 페이지와 Java가 통신할 때 객체를 변환하는 역할을 한다.

@RequestBody vs @ResponseBody

  • @RequestBody : HTTP 요청의 body 내용을 Java 객체로 변환할 때 사용한다.

    • 이 어노테이션이 붙은 파라미터에는 http요청의 본문(body)이 그대로 전달된다.
      (xml이나 json기반의 메세지를 사용하는 경우 이 방법이 매우 유용)
    • HTTP 요청의 바디 내용을 통째로 자바객체로 변환해서 매핑된 메소드 파라미터로 전달한다.
  • @ResponseBody : Java 객체의 내용을 HTTP 요청의 body로 변환할 때 사용한다.

    • 자바객체를 HTTP요청의 바디 내용으로 매핑하여 클라이언트로 전송한다.
    • 해당 어노테이션이 붙은 파라미터가 있으면 HTTP요청의 미디어타입과 파라미터의 타입을 먼저 확인한다.

즉, 클라이언트에서 서버로 필요한 데이터를 요청하기 위해 JSON 데이터를 요청 본문에 담아 서버로 보내면, 서버에서는 @RequestBody 어노테이션을 사용하여 HTTP 요청 본문에 담긴 값들을 자바객체로 변환시켜, 객체에 저장한다.

서버에서 클라이언트로 응답 데이터를 전송하기 위해 @ResponseBody 어노테이션을 사용하여 자바 객체를 HTTP 응답 본문의 객체로 변환하여 클라이언트로 전송한다.

@RestController 를 사용하는 경우에는 자동으로 return 값에 ResponseBody를 붙여 자바 객체가 매핑되어 전달되기 때문에 @ResponseBody의 생략이 가능하다!!!

Rest API를 구현하기에 앞서..

여기서 구현할 Rest API 의 주소 설계

  • GET /api/articles : article 목록 조회
  • GET /api/articles/{id} : article 단일 조회
  • POST /api/articles : 생성
  • PATCH /api/articles/{id} : 수정
  • DELETE /api/articles/{id} : 삭제

주소 설계가 끝났다면, 요청을 받아 JSON으로 반환해줄 Controller가 필요 => "REST 컨트롤러"

  • @RestController : Rest API용 컨트롤러, JSON 반환

    • 일반 Controller vs Rest Controller 의 차이 : 반환하는 게 다름
      : 일반 @Controller 는 View 템플릿 페이지를 반환하지만, @RestController 는 (일반적으로) JSON(데이터)를 반환함
      Talend API Tester 로 요청을 보내보면 Body에 실려오는 데이터가 다른 것을 확인할 수 있음
  • ResponseEntity : Spring MVC에서 HTTP 요청에 대한 응답을 제어하는 데 사용하는 클래스.

    • 이 클래스는 Response Body, Header, Status Code 를 포함할 수 있어, 세밀한 응답 관리를 가능하게 한다. ResponseEntity는 @ResController와 함께 사용되어 JSON 또는 XML 같은 RESTful 서비스를 제공하는 데 이상적이다.
ResponseEntity<T> responseEntity = new ResponseEntity<>(body, headers, status);
  • T : Response Body의 타입
  • body : Response Body 객체
  • headers : 설정할 HTTP Header
  • status : HTTP Response Status Code

💻 실습

api 패키지 생성 > ArticleApiController.java 파일 생성

1. GET /api/articles : article 목록 조회

파일명 : api/ArticleApiController.java

//GET - 전체 article 조회
@GetMapping("/api/articles")
public List<Article> index(){
	return articleRepository.findAll();
}

2. GET /api/articles/{id} : article 단일 조회

//GET - 단일 article 조회
@GetMapping("/api/articles/{id}")
public Article index(@PathVariable Long id){
	return articleRepository.findById(id).orElse(null);
}


3. POST /api/articles : 생성

//POST - 생성
@PostMapping("/api/articles")
public ResponseEntity<Article> create(@RequestBody ArticleForm dto){
    Article saved = articleRepository.save(dto.toEntity());
    return ResponseEntity.status(HttpStatus.CREATED).body(saved);
}
  • @RequestBody : 이 어노테이션이 붙은 파라미터에는 http 요청의 본문(body)이 그대로 전달된다. 따라서 이 요청 본문(request body)에 담긴 값을 자바 객체로 변환한다.
    (이전에는 페이지에서 form 데이터로 넘겨주었으므로 해당 어노테이션을 사용하지 않았지만, 지금은 Rest API를 사용해 JSON 데이터를 넘겨주므로 필요)

4. PATCH /api/articles/{id} : 수정

//PATCH
@PatchMapping("/api/articles/{id}")
public ResponseEntity<Article> update(@RequestBody ArticleForm dto,
                                     @PathVariable Long id){
    //1. 수정용 엔티티 생성
    Article updated_article = dto.toEntity();

    //2. 대상 엔티티 조회
    Article target = articleRepository.findById(id).orElse(null);

    //3. 잘못된 요청 처리 (대상이 없거나, (요청 url과 body의)id가 다른 경우)
    if(target == null || id != updated_article.getId()){
        //400, 잘못된 요청 응답 보내기
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); //BAD_REQUEST = 400
    }

    //4. 업데이트 및 정상 응답(200)
    Article updated = articleRepository.save(updated_article);
    return ResponseEntity.status(HttpStatus.OK).body(updated); //OK = 200
}

자, 그런데 이렇게 하면 한 가지 문제가 있다.
수정은 정상적으로 작동하지만, 만약 요청하는 body에 어떤 데이터를 하나 빼먹는다면?

사진과 같이 title을 빼먹고 보내면 수정된 게시글은 title이 null 값을 가지게 된다.
따라서 이 문제를 해결하기 위해, entity 파일에서 patch 라는 함수를 만들어 '수정된 데이터만 기존 데이터에 붙여(patch)주는' 방식으로 동작하게 해보자.

파일명 : entity/Article.java
  
public void patch(Article updatedArticle) {
    if(updatedArticle.title != null)
        this.title = updatedArticle.title;
    if(updatedArticle.content != null)
        this.content = updatedArticle.content;
}

body 에서 id 를 빼먹으면 어쩌죠? -> body에 id가 없으면 '잘못된 요청 처리'하는 코드에서 id가 다른 경우로 400처리 돼서 어차피 수정 안돼요~

patch 메서드를 추가했으니 돌아와서 마무리 코드를 작성해보자.

//4. 업데이트 및 정상 응답(200)
target.patch(updated_article);
Article updated = articleRepository.save(target);
return ResponseEntity.status(HttpStatus.OK).body(updated); //OK = 200

patch 메서드에서 this를 통해 해당 데이터에 입력되게끔 코드를 짰으니 save(updated_article) -> save(target)으로 변경해주면 된다.

title 을 빼먹어도 null 이 아닌 기존 데이터 "가가가가"가 유지되는 것을 확인할 수 있다. 성공!

5. DELETE /api/articles/{id} : 삭제

//DELETE - 삭제
@DeleteMapping("/api/articles/{id}")
public ResponseEntity<Article> delete(@PathVariable Long id){
    //1. 대상 찾기
    Article target = articleRepository.findById(id).orElse(null);

    //2. 잘못된 요청 처리
    if(target == null){
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
    }

    //3. 대상 삭제
    articleRepository.delete(target);
    return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
  • ResponseEntity.status(HttpStatus.OK).build() : 몸체 내용이 없다면 다음과 같이 body를 지정하지 않고 build()로 바로 생성해도 된다.


📚정리

1. @RestController

  • Rest API 용 컨트롤러로, 일반 Controller는 view 페이지를 반환하지만 RestController는 주로 JSON 데이터를 반환한다.

2. ResponseEntity

  • HTTP 요청에 대한 응답을 제어하는 데 사용하는 클래스로, Response Body, Header, Status Code를 포함할 수 있어 세밀한 응답 관리를 가능케 한다.
  • (왜 사용할까?) 지금까지는 반환 타입을 일반 객체로 해왔지만 ResponseEntity를 사용함으로서 내가 반환 값을 커스텀할 수 있다. 예를 들어 어떤 문제가 생겼을 때 서버 내부의 보안을 위해 상태 코드를 바꿔서 줄 수 있고, body에도 특정 메시지만 담아서 줄 수 있는 것이다.

강의 출처 : https://www.youtube.com/watch?v=_vDACE13Ubc&list=PLyebPLlVYXCiYdYaWRKgCqvnCFrLEANXt&index=1 [스프링 부트 입문 - 홍팍]

참고 사이트
https://cheershennah.tistory.com/179 - 클라이언트-서버 비동기 통신 & @RequestBody 와 @ReponseBody 의 차이
https://burningfalls.github.io/java/what-is-response-entity/ - ResponseEntity 란?

profile
p(´∇`)q

0개의 댓글