- REST API의 구현 과정
- 조회 요청 : /api/articles 또는 /api/articles/{id}
→ GET 메서드로 Article 목록 전체 또는 단일 Article을 조회 - 생성 요청 : /api/articles
→ POST 메서드로 새로운 Article을 생성해 목록에 저장 - 수정 요청 : /api/articles/{id}
→ PATCH 메서드로 특정 Article의 내용을 수정 - 삭제 요청 : /api/articles/{id}
→ DELETE 메서드로 특정 Article의 내용을 삭제
- 조회 요청 : /api/articles 또는 /api/articles/{id}
REST API 구현하기
- REST 컨트롤러 맛보기
- api 패키지를 생성후 FirstApiController.java 파일 생성
- REST API를 구현할떄는 @Controller(일반 컨트롤러) 대신 @RestController(REST 컨트롤러) 을 사용
- localhost:8887/api/hello로 URL 요청이 들어왔을때 HELLO WORLD! 를 출력하는 메서드 작성
- 서버를 실행하고 localhost:8887/api/hello에 접속하면 문자열이 잘 반환됨
- Talend API Tester 에서도 GET메서드를 선택후 URL을 localhost:8887/api/hello 으로 입력후 SEND버튼 클릭
- 응답이 200으로 돌아옴 BODY 부분에 HELLO WORLD!가 반환
@RestController // REST API용 컨트롤러
public class FirstApiController {
@GetMapping("/api/hello") //URL 요청 접수
public String hello() {
return "HELLO WORLD!"; //문자열 반환
}
}
- REST 컨트롤러와 일반 컨트롤러의 차이
- 일반 컨트롤러는 뷰 페이지를 반환
- REST 컨트롤러는 JSON이나 텍스트같은 데이터를 반환
- REST API : GET 구현하기
- 모든 게시글 조회하기
- 새로운 REST 컨트롤러를 api 패키지 안에 ArticleApiController.java 파일 생성
- @RestController 어노테이션을 추가함
- GET 요청을 처리하는 메서드를 생성
- @GetMapping으로 URL 요청은 "/api/articles"로 작성
- 메서드의 수행 결과로는 Article 묶음을 반환하므로 반환형이 List<Article>인 index() 메서드를 정의후 return문에는 articleRepository의 findAll() 메서드를 사용해 DB에 저장된 모든 Article을 반환
- findAll() 메서드를 사용하기 위해서 클래스 내부에 articleRepository을 선언후 @Autowired 어노테이션을 붙여 의존성 주입
- 모든 게시글 조회하기
@RestController // REST 컨트롤러 선언
public class ArticleApiController {
@Autowired // 게시글 리파지터리 주입
private ArticleRepository articleRepository;
@GetMapping("/api/articles") //URL 요청 접수
public List<Article> index(){ //index() 메서드 정의
return articleRepository.findAll();
}
}
- REST API : GET 구현하기
- 단일 게시글 조회하기
- 조회하려는 게시글의 id에 따라 URL 요청이 바뀌어야 하므로 @GetMapping 의 URL을 "/api/articles/{id}"로 작성
- 메서드 수행 결과로 단일 Article을 반환하므로 반환형은 Article로 작성 후 메서드 이름을 show()로 작성후 return문은 DB에서 id로 검색해 얻은 엔티티를 가져오고 만약 해당 데이터가 없으면 null을 반환하도록 작성
- DB에서 id로 검색하려면 매개변수로 id를 받아와야하기 때문에 주소에서 받아올수 있도록 매개변수 앞에 @PathVariable 을 붙임
- 단일 게시글 조회하기
@GetMapping("/api/articles/{id}")
public Article show(@PathVariable Long id) {
//주소에 있는 id를 가져올수 있도록 @PathVariable을 작성
return articleRepository.findById(id).orElse(null);
}
- REST API : POST 구현하기
- 데이터 생성 요청을 받아 처리할 메서드를 생성
- @PostMapping 으로 "/api/articles" 주소로 오는 URL 요청을 받음
- 반환형이 Article 인 create()라는 메서드 정의하고 생성할 데이터를 dto 매개변수로 받아옴
- POST 요청을 보내면 성공 응답이 오긴하지만 응답 본문에 title , content 과 null값으로 나옴
- dto 매개변수 앞에 @RequestBody 라는 어노테이션 추가하면 요청시 본문(BODY)에 실어 보내는 데이터를 create() 메서드의 매개변수로 받아올수 있음
- 생성자 문제가 있어서 ArticleForm 에 @NoArgsConstructor ,@Getter ,@Setter 추가로 작성
- 데이터 생성 요청을 받아 처리할 메서드를 생성
@PostMapping("/api/articles")
public Article create(@RequestBody ArticleForm dto) { //create() 메서드 정의
Article article = dto.toEntity();
return articleRepository.save(article);
}
- REST API: PATCH 구현하기
- 데이터 전체를 수정할 경우
- 데이터 수정 요청을 받아 처리할 메서드를 생성
- @PatchMapping 으로 "/api/articles/{id}" 주소로 오는 URL 요청 받음
- 반환형인 Article 인 update() 메서드 정의후 매개변수로 요청 URL의 id와 요청 메세지의 본문 데이터를 받아옴
- 메서드의 본문은 네 부분으로 나누어 작성
- 수정용 엔티티 생성
- 클라이언트에서 받은 수정 데이터가 담긴 dto를 DB에서 활용할 수 있도록 엔티티로 변환해 article 변수에 저장
- 실행이 잘 되는지 학인하기 위해 id와 article의 내용을 로그로 찍기 위해 클래스위에 @Sif4j어노테이션 추가
- DB에서 대상 엔티티를 조회해 가져오기 위해 articleRepository.findById(id)을 통해서 DB에서 해당 id를 가진 엔티티를 가져오되 없다면 null을 반환 , 이렇게 반환한 값은 target이라는 변수에 저장
- 잘못된 요청이 들어온 경우 처리하기 위한 코드 작성
- 대상 엔티티가 없거나 수정 요청 id 와 본문 id가 다를경우 잘못된 요청 이므로 조건문 실행
- 잘못된 요청임을 확일할 수 있도록 id와 article의 내용을 로그로 찍음
- 클라이언트 요청 오류이므로 상태 코드 400을 반환해야하지만 단순히 반환형이 Article로 하면 안되서 ResponseEntity에 Article을 담아서 반환해야만 하는 데이터에 상태 코드를 실어 보낼수 있음
- if 문의 실행 결과 ResponseEntity 의 상태에는 400 또는 HttpStatus.BAD_REQUEST를 , 본문에는 반환할 데이터가 없으므로 null을 실어 반환
- 정상 응답을 처리
- article 엔티티에 담긴 수정용 데이터를 DB에 저장한 후 updated 라는 변수에 저장
- 수정된 데이터는 ResponseEntity에 담아서 보냄 이때 정상 응답이므로 상태에는 200 또는 HttpStatus.OK를 싣고 본문에는 받환할 데이터인 updated를 싣는다
- 수정용 엔티티 생성
- 데이터 수정 요청을 받아 처리할 메서드를 생성
- 데이터 전체를 수정할 경우
@PatchMapping("/api/articles/{id}")
public ResponseEntity<Article> update(@PathVariable Long id , @RequestBody ArticleForm dto ) {
// 1. DTO -> 엔티티 변환하기
Article article = dto.toEntity(); // dto를 엔티티로 변환
log.info("id: {}, article: {}", id, article.toString());
// 2. 타깃 조회하기
Article target = articleRepository.findById(id).orElse(null);
// 3. 잘못된 요청 처리하기
if(target == null || id != article.getId()) { //잘못된 요청인지 판별
// 400, 잘못된 요청 응답
log.info("잘못된 요청! id: {}, article: {}", id, article.toString());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
// 4. 업데이트 및 정상 응답(200)하기
Article updated = articleRepository.save(article); //article 엔티티 DB에 저장
return ResponseEntity.status(HttpStatus.OK).body(updated);
}
2023-12-11 16:03:11.639 INFO 1772 --- [nio-8887-exec-5] c.e.f.api.ArticleApiController : 잘못된 요청! id: 1, article: Article(id=3, title=생성하기, content=들어갔2다)
REST API: PATCH 구현하기
- 일부 데이터만 수정할 경우
- title을 빼고 보내면 성공 응답은 오지만 title 값이 null이되며 기존 데이터가 날아가기 때문에 코드를 보강해 작성
- 앞에서 클라이언트로부터 받은 수정 요청 데이터를 article에 저장 그리고 수정할 대상을 DB에서 조회해 target에 저장되있으므로 기존 데이터에 새 데이터를 붙여주면 일부 데이터만 수정 가능
- 만약 patch()라는 메서드가 있다고 가정하고 target에 patch() 메서드로 article(수정할 내용만)을 붙임
- 최종적으로 target을 DB에 저장
- entity 패키지 안에 있는 Article.java을 열고 patch() 메서드 추가
- patch() 메서드는 수정할 내용이 있는 경우에만 동작하도록 if문으로 title이 null이 아니면 this(target)의 title을 갱신 같은 방법으로 content도 갱신
//Article.java 파일에 patch() 메서드 추가
public void patch(Article article) {
if (article.title != null)
this.title = article.title;
if (article.content != null)
this.content = article.content;
}
//ArticleApiController 에 있는update 메서드를 이렇게 수정
@PatchMapping("/api/articles/{id}")
public ResponseEntity<Article> update(@PathVariable Long id , @RequestBody ArticleForm dto ) {
// 1. DTO -> 엔티티 변환하기
Article article = dto.toEntity(); // dto를 엔티티로 변환
log.info("id: {}, article: {}", id, article.toString());
// 2. 타깃 조회하기
Article target = articleRepository.findById(id).orElse(null);
// 3. 잘못된 요청 처리하기
if(target == null || id != article.getId()) { //잘못된 요청인지 판별
// 400, 잘못된 요청 응답
log.info("잘못된 요청! id: {}, article: {}", id, article.toString());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
// 4. 업데이트 및 정상 응답(200)하기
target.patch(article); // <==== 수정된 부분
Article updated = articleRepository.save(target); // <==== 수정된 부분
return ResponseEntity.status(HttpStatus.OK).body(updated);
}
- REST API : DELETE 구현하기
- DELETE 요청을 받아 처리할 메서드를 생성
- @DeleteMapping으로 "/api/articles/{id}" URL 요청을 받음
- 반환형으로 ResponseEntity에 <Article>을 실어 보내는 delete()라는 메서드를 정의하고 URL의 id를 매개변수로 받아옴
- 메서드는 세 부분으로 나누어 작성
- DB에서 대상 엔티티가 있는지 조회하고 없으면 null을 반환 반환받은 값은 target이라는 변수에 저장
- 잘못된 요청을 처리하는 코드를 작성 즉 target이 null이면 ResponseEntity의 상태에는 BAD_REQUEST 본문에는 null을 실어 보냄
- 잘못된 요청이 아니라면 찾은 대상 엔티티를 삭제 그리고 ResponseEntity의 상태에는 httpStatus.OK 본문에는 null을 실어 보냄
- return 문의 body(null) 대신 build()으로 작성 가능
- ResponseEntity의 build() 메서드는 HTTP 응답의 body가 없는 ResponseEntity 객체를 생성
- 따라서 bulid() 메서드로 생성된 객체는 body(null)의 결과와 같음
- 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.OK).body(null);
//return ResponseEntity.status(HttpStatus.OK).build(); 위에랑 같은 결과
}
'BE > 스프링 부트 3' 카테고리의 다른 글
13장 테스트 코드 작성하기 (1) | 2023.12.19 |
---|---|
12장 서비스 계층과 트랜잭션 (0) | 2023.12.16 |
10장 REST API 와 JSON (0) | 2023.12.10 |
9장 CRUD와 SQL 쿼리 종합 (0) | 2023.12.06 |
8장 게시글 삭제하기: Delete (2) | 2023.12.02 |