intro :
∨ 지난시간에 모했나
: 연습용 RestAPI 서버를 통해 http 요청/응답 실습했다.
: 그리고 Rest API의 응답 표준인 json 개념도 알았다.
∨ 참고) 보충! Status code는 크게 5분류된다.
1xx : informational
2xx : successful | 200(OK), 201(Created)
3xx : redirection
4xx : client error | 404(Not Found)
5xx : sever error | 500(Internal Server Error)
이번 내용:
기존 Article 데이터를 CRUD하기 위한 Rest API 구현하기
먼저 Rest API 주소를 설계한다.
그냥.. 이런거 정하자는 거다.
∨ GET 요청을 보낼 url
- /api/articles
- /api/articles/{id}
∨ POST 요청을 보낼 url
- /api/articles
∨ PATCH 요청을 보낼 url
- /api/articles/{id}
∨ DELETE 요청을 보낼 url
- /api/articles/{id}
이렇게 주소설계한 다음에 실습 고고!!
이번 실습
+ 요청을 받아 json으로 반환해줄 컨트롤러 만들어줄거임 RestController
+ 적절한 status code 반환을 위한 클래스인 ResponseEntity를 사용해보자.
Rest API 구현하기 실습 시쟉쟉
REST api에 대한 개념은 맨 아래 살짝 정리해두었다.
@RestController
컨트롤러를 하나 만들어 줄건데
이전에는 일반 컨트롤러 @Controller를 썼지만 이제부터는 @RestController 써줄 거다.
@Controller : 뷰 템플릿 페이지를 반환함 (html)
@RestController : 일반적으로 JSON을 반환한다. String을 반환할 수도 있다.
중요한 것은 '데이터를 반환'한다는 것!
∨ 간단예시
@RestController
public class FirstApiController {
@GetMapping("/api/hello")
public String hello() {
return "hello world!";
}
}
cf. 구체적으로 무슨 응답을 반환하는지는
저번에 해본 '연습용 API 서버'에서 확인해보면 된다 >v <
자 이렇게 @RestController가 뭔지 알았다능
note_ 우리가 하고 있는 것은
"기존 Article 데이터를 CRUD하기 위한 Rest API 구현하기"라는 것을 다시한번 상기하고 가자.
=> rest API용 컨트롤러를 구현하자.
ArticleApiController
@RestController
public class ArticleApiController{ ... }에다가 CRUD 기능을 구현해 줄 것이다.
note_ 이 컨트롤러는 JSON을 반환한다는 것도 잊지 말자
자 이제부터 컨트롤러에 GET, POST, PATCH, DELETE를 구현하자.
recall) 컨트롤러가 웹(http 프로토콜)의 4가지 요청을 처리
recall) 컨트롤러에 Repository를 멤버로 두고 썼던 걸 기억하자
recall) JPA의 Repository를 통해 server와 DB간 소통을 한다는 것도 기억하자
● GET 요청 처리
일단 컨트롤러에 GET요청 처리를 구현하기 전에 api 테스터에서 http 요청을 보내보자.
GET http://localhost:8080/api/articles 요청을 보내면 404(not found) 에러를 만날 수 있다.
위 url에 대한 get요청 처리를 안 했기 때문이다. 구럼 이제 구현시쟉 >v <
모든 articles 내용을 read하여 json 데이터로 받도록 GET 요청을 처리해보자.
모든 목록을 조회
@GetMapping("/api/articles")
public List<Article> index() {
return articleRepository.findAll();
}
단일 Entity를 조회
@GetMapping("/api/articles/{id}")
public Article show(@PathVariable Long id) {
return articleRepository.findById(id).orElse(null);
}
원하는대로 매핑해준 뒤,
url 요청을 보낸 결과를 보면 articles데이터가 json형식으로 잘 담겨 응답한다.
http 응답의 body를 보아도 데이터가 json형식으로 실려온 것을 확인가능하다.
● POST 요청 처리
POST http://localhost:8080/api/articles 요청을 보낸다고 하자.
body에 json 데이터를 실어서 보내자.
{
"title": "배스킨최애맛",
"content": "체리쥬빌레는 사람을 주겨!!"
}
아래의 @PostMapping이 해당 url에서의 POST 요청을 받는다.
@PostMapping("/api/articles")
public Article create(@RequestBody ArticleDto dto) {
Article article = dto.toEntity();
return articleRepository.save(article);
}
※ 폼에서 데이터를 던질 때에는 파라미터에서 dto로 받아오는데
rest API에서 json으로 데이터를 던질 때에는 @RequestBody 어노테이션을 표시해주어야 받을 수 있다.
※ @RequestBody : JSON 데이터 받기
ㄴ 요청의 body에서 데이터를 받아오란 의미
DB에서 확인해보면, 데이터가 잘 추가된 것을 확인 가능!
● PATCH 요청 처리
PATCH http://localhost:8080/api/articles/1 요청을 보내자.
body에는 patch할 내용을 json으로 넣어 보내면 되겠다.
{
"id": 1,
"title": "난바뀌었다",
"content": "누가나를바꿧느냐"
}
@PatchMapping("/api/articles/{id}")
public Article update(@PathVariable Long id,
@RequestBody ArticleDto dto) {
// 수정용 Entity 생성
Article article = dto.toEntity();
// 대상 Entity 조회
Article target = articleRepository.findById(id).orElse(null);
// 잘못된 요청을 처리 (대상이 없음 || 요청url의 id != 수정대상 id)
if (target == null || id != article.getId()) {
retrun ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
// 정상적으로 업데이트 및 정상 응답(200)
Article updated = articleRepository.save(article);
return ResponseEntity.status(HttpStatus.OK).body(updated);
}
※ 응답 status를 리턴하는 방법?
이 update 메서드의 반환타입이 순수 Article이면 안되고,
ResponseEntity에 담아서 반환해야 한다.
즉 반환타입을 ResponseEntity<Article>로 설정하자.
그럼 여기에 '상태코드'를 담아 반환할 수 있다.
.
.
∨ 더 생각해볼 것:
PATCH시 데이터를 누락해서 보내면 어떻게 될까?
id, title, content에 값을 담아 보내야 하는데 만약 title을 누락했다면 null이 담겨서 간다.
이 문제를 보강하려면 어떻게 해야 할까?
수정되어 들어온 json 데이터만 patch하고, 빠진 데이터는 기존데이터로 유지하면 좋지 않을까?
given :
수정 내용을 담은 Entity 존재
수정 대상 Entity
when :
수정 요청이 올바르다면 (id가 유효함 등)
then :
수정대상 Entity에 수정내용 Entity를 덮어씌운다!
명시한 내용만 수정되도록..
=> then에 해당하는 기능을 추가해보자.
메서드를 어디에 넣어야 할까?
자연스럽게 Entity 클래스에 넣으면 된다.
그 Entity 데이터에 대한 patch가 이루어지는 거니까..
public class Article {
...
public void patch(Article article) {
if (article.title != null)
this.title = article.title;
if (article.content != null)
this.content = article.content;
}
}
그럼 이제 컨트롤러에서
target.patch(article);
Article updated = articleRepository.save(target);
return ResponseEntity.status(HttpStatus.OK).body(updated);
이런식으로 수정할 것만 수정해서 넣어줄 수 있다.
● DELETE 요청 처리
DELETE http://localhost:8080/api/articles/1 요청을 보내자..
@DeleteMapping("/api/article/{id}")
public ResponseEntity<Article> delete(@PathVariable Long id) {
// 대상 찾기
Article target = articleRepository.findById(id).orElse(null);
// 잘못된 요청 처리
if (target == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
// 대상 삭제
articleRepository.delete(target);
// 데이터 반환
return ResponseEntity.status(HttpStatus.OK).build();
}
그취.. ㅡ
DB에서 확인해보면 2번이 사라진 거 확인 ㄱㄴ
우왓 짱신기 ~.~
↓ 약간 감이 덜 와서 다시 정리하며 이해하겠다.
지금 실습은 Rest api를 적용해서 CRUD를 구현한 것이다.
Rest api를 적용했다는 것은 Representational State Transfer 방식 즉 REST의 원리를 따르게끔 api를 설계하여 적용한 것이다. 참고로 REST 원리와는 별개로 REST api의 설계 규칙도 지켜야 진정하게 RESTful한 설계를 한 것이다.
위 말을 이해하려면 REST의 원리는 무엇이며 REST api의 설계 규칙은 뭔지 알아야겠다.
일단 REST의 핵심 개념은 "자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것"이다.
좀 더 자세히 말하면 REST란,
- HTTP URI를 통해 자원을 '명시'하고
- HTTP의 4가지 메서드인 POST, GET, PUT, DELETE를 통해
- 해당 자원(URI에 명시)에 대한 CRUD를 적용하는 것을 의미한다.
더 자세한 내용,
예를들면 REST api 개념과 설계 규칙 등은 링크를 보기 >v <
+ 참고 : 지난 시간에는 REST api라는 걸 이렇게 알고 들어갔다.
REST api 적용의 결과적인 개념만을 간단히 알고 실습시작한 것 같다.
그래서 더 어렵지 않게 실습할 수 있었다.
자세한 개념은 추후 보강하자.
오예!~
일단은 진도 먼저 쭉쭉 나가고
나중에 실제 프로젝트 진행할 때 RESTful하게 설계하며 개념을 더 확실히 하도록 하쟈
json과 REST 개념이 어떻게 연관되는지도 그때 공부하도록 하자.
꼭 그러쟈
'web +a' 카테고리의 다른 글
스프링부트 ~21 | 테스트코드 작성 관련 (0) | 2022.07.25 |
---|---|
스프링부트 ~20 | 서비스 계층 추가 & 트랜잭션 처리 (0) | 2022.07.25 |
스프링부트 ~18 | REST API와 JSON (0) | 2022.07.21 |
스프링부트 ~17 | SQL 쿼리 로깅 & CRUD 쿼리 실습 (0) | 2022.07.20 |
스프링부트 ~16 | Delete (0) | 2022.07.20 |