RestController 와 HTTP
오늘은 ResController를 이용하여 데이터의 CRUD처리를 배워볼 것이다.
RestController란 서버와 DB의 데이터 이동을 위해 만들어진 Controller로 일반 Controller는 뷰페이지와 연결이 되지만, RestController는 JSON(데이터)을 반환하는 RestAPI Controller이다.
RestController 에서는 GET, POST, PATCH, UPDATE, DELETE 등의 메서드를 사용할 수 있다.
RestController를 작성하여 연습해보았다.
ArticleApiController.java
package com.example.springstudy.api;
import com.example.springstudy.entity.Article;
import com.example.springstudy.dto.ArticleForm;
import com.example.springstudy.repository.ArticleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Scanner;
@RestController
@Slf4j
public class ArticleApiController {
@Autowired // DI 외부에서 가져온다. (의존관계 주입)
private ArticleRepository articleRepository;
// GET
// 게시글 페이지 (메인 페이지)
@GetMapping("/api/articles")
public List<Article> index() {
return articleRepository.findAll();
}
// 게시글 상세 페이지
@GetMapping("/api/articles/{id}")
public Article index(@PathVariable Long id) {
return articleRepository.findById(id).orElse(null);
}
// POST (게시글 추가)
@PostMapping("/api/articles")
public Article create(@RequestBody ArticleForm dto) { // @RequestBody -> JSON 데이터 받기
Article article = dto.toEntity();
return articleRepository.save(article);
}
// PATCH (게시글 수정)
@PatchMapping("/api/articles/{id}")
public ResponseEntity<Article> edit(@PathVariable Long id, @RequestBody ArticleForm dto){
// Article을 담아서 ResponseEntity로 리턴 값을 보내야 한다. 그래야 응답 코드를 반환할 수 있다.
// ResponseEntity에 Article이 담겨서 JSON으로 반환이 된다.
// 1. 수정용 Entity 생성
Article article = dto.toEntity();
// 2. 대상 Entity 조회
Article target = articleRepository.findById(id).orElse(null);
// 3. 잘못된 요청 처리(대상이 없거나, id가 없는경우)
if( target != null || id != target.getId()) {
// 400 요청, 잘못된 응답 요청!
log.info("잘못된 응답 요청! id: {}, articles: {}", id, article.toString());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // BAD_REQUEST = 400번 코드 반환
}
// 4. 업데이트 및 정상 응답(200)
target.patch(article);
Article updated = articleRepository.save(target);
return ResponseEntity.status(HttpStatus.OK).body(updated);
}
// DELETE
@DeleteMapping("/api/articles/{id}")
public ResponseEntity<Article> delete(@PathVariable Long id){
// 대상 Entity 조회
Article target = articleRepository.findById(id).orElse(null);
// 대상 Entity 삭제
// 대상 Entity 가 null일 경우 400번 오류 코드 반환
if(target == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // BAD_REQUEST = 400번 코드 반환
}
// 데이터 반환
articleRepository.delete(target);
return ResponseEntity.status(HttpStatus.OK).build();
}
}
// 게시글 페이지 (메인 페이지)
@GetMapping("/api/articles")
public List<Article> index() {
return articleRepository.findAll();
}
// 게시글 상세 페이지
@GetMapping("/api/articles/{id}")
public Article index(@PathVariable Long id) {
return articleRepository.findById(id).orElse(null);
}
public List<Article> index()
@PathVariable Long id
articleRepository.findById(id).orElse(null);
// POST (게시글 추가)
@PostMapping("/api/articles")
public Article create(@RequestBody ArticleForm dto) {
Article article = dto.toEntity();
return articleRepository.save(article);
}
public Article create(@RequestBody ArticleForm dto)
Article article = dto.toEntity();
return articleRepository.save(article);
// PATCH (게시글 수정)
@PatchMapping("/api/articles/{id}")
public ResponseEntity<Article> edit(@PathVariable Long id, @RequestBody ArticleForm dto){
// Article을 담아서 ResponseEntity로 리턴 값을 보내야 한다. 그래야 응답 코드를 반환할 수 있다.
// ResponseEntity에 Article이 담겨서 JSON으로 반환이 된다.
// 1. 수정용 Entity 생성
Article article = dto.toEntity();
// 2. 대상 Entity 조회
Article target = articleRepository.findById(id).orElse(null);
// 3. 잘못된 요청 처리(대상이 없거나, id가 없는경우)
if( target != null || id != target.getId()) {
// 400 요청, 잘못된 응답 요청!
log.info("잘못된 응답 요청! id: {}, articles: {}", id, article.toString());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // BAD_REQUEST = 400번 코드 반환
}
// 4. 업데이트 및 정상 응답(200)
target.patch(article);
Article updated = articleRepository.save(target);
return ResponseEntity.status(HttpStatus.OK).body(updated);
}
@PatchMapping("/api/articles/{id}")
public ResponseEntity<Articles> edit(@PathVariable Long id, @RequestBody articleForm dto)
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
target.patch(article)
Article.java(Entity 클래스)
// patch 요청 받은 함수 ( article의 title이나 content가 null값이 아니라면 Entity에 값을 넣어준다.)
public void patch(Article article) {
if (article.title != null)
this.title = article.title;
if(article.content != null)
this.content = article.content;
}
// DELETE
@DeleteMapping("/api/articles/{id}")
public ResponseEntity<Article> delete(@PathVariable Long id){
// 대상 Entity 조회
Article target = articleRepository.findById(id).orElse(null);
// 대상 Entity 가 null일 경우 400번 오류 코드 반환
if(target == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // BAD_REQUEST = 400번 코드 반환
}
// 데이터 삭제 및 반환
articleRepository.delete(target);
return ResponseEntity.status(HttpStatus.OK).build();
}
if(target == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
return ResponseEntity.status(HttpStatus.OK).build();
ResponseEntity란, HttpEntity를 상속받는, 결과 데이터와 HTTP 상태 코드를 직접 제어할 수 있는 클래스이다.
ResponseEntity에는 사용자의 HttpRequest에 대한 응답 데이터가 포함된다.
에러 코드와 같은 HTTP상태 코드를 전송하고 싶은 데이터와 함께 전송할 수 있기 때문에 좀 더 세밀한 제어가 필요한 경우 사용한다고 합니다.
public ResponseEntity<Article> save(){
}
라는 메서드가 있을 때, Article이라는 데이터를 담아서 해당 데이터에 대한 오류 코드와 데이터를 반환할 수 있다.
API 개발 시 올바른 상태코드를 응답하는 것은 매우 중요하다
-> 클라이언트가 어느 부분에서 잘못 입력을 했는지 알려줄 수 있기 때문에 반환값을 상태 코드 값으로 만들면 좋다.
상태 코드를 반환하기 위해서는 ResponseEntity를 사용하여 반환한다.
References (참고 자료)
https://www.inflearn.com/course/%EA%B0%9C%EB%85%90%EC%8B%A4%EC%8A%B5-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-
https://thalals.tistory.com/268