개발환경 준비
이용한 maven 라이브러리
- jackson-databind : 버전 - 2.8.5
- lombok : 버전 - 1.16.10
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
Controller생성
-RestApiController.java
@RestController // @Controller + @ResponseBody
@RequestMapping("/api")
public class RestAPIController {
@Autowired
UserService userService;
// --- Retrieve All Users 모든 사용자 조회
@RequestMapping(value="/users", method=RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers(){ // header, body(json), HTTP.status
List<User> users = userService.findAllUsers();
if(users.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<User>>(users, HttpStatus.OK); // body에 users.
}
// --- Retrieve Single User 한 사용자 조회 // template valuable
@RequestMapping(value="/users/{id}", method=RequestMethod.GET)
public ResponseEntity<User> getUser(@PathVariable("id") long id){
User user = userService.FindById(id);
if(user == null) {
//do to list : exception (예외처리)
throw new UserNotFoundException(id);
}
return new ResponseEntity<User>(user, HttpStatus.OK); // body에 users.
}
// --- Create a User
@RequestMapping(value="/users", method=RequestMethod.POST) // request body(json)
public ResponseEntity<Void> createUser(@RequestBody User user, // body부분은 없음을 Void로 표시
UriComponentsBuilder ucBuilder){ // 새롭게 생성된 사용자의 uri를 header정보에 담아서 넘겨주기 위함
if(userService.isUserExist(user)) {
throw new UserDuplicatedException(user.getName());
}
userService.saveUser(user);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/api/users/{id}")
.buildAndExpand(user.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
// --- Update a User
@RequestMapping(value="/users/{id}", method = RequestMethod.PUT)
public ResponseEntity<User> updateUser(@PathVariable("id")long id,
@RequestBody User user ){
User currentUser = userService.FindById(id);
if(currentUser == null) {
throw new UserNotFoundException(id);
}
currentUser.setName(user.getName());
currentUser.setAge(user.getAge());
currentUser.setSalary(user.getSalary());
userService.updateUser(currentUser);
return new ResponseEntity<User>(currentUser, HttpStatus.OK);
}
// --- Delete a User
@RequestMapping(value="/users/{id}", method = RequestMethod.DELETE)
public ResponseEntity<User> deleteUser(@PathVariable("id")long id){
User user = userService.FindById(id);
if(user == null) {
throw new UserNotFoundException(id);
}
userService.deleteUserById(id);
return new ResponseEntity<User>( HttpStatus.NO_CONTENT);
}
// --- Delete a User
@RequestMapping(value="/users", method = RequestMethod.DELETE)
public ResponseEntity<User> deleteAllUsers(){
userService.deleteAllUsers();
return new ResponseEntity<User>( HttpStatus.NO_CONTENT);
}
}
@RestController
- -@Controller + @ResponseBody 를 합친 어노테이션
- RestController의 주용도는 Json 형태로 객체 데이터를 반환하는 것이다..
데이터를 응답으로 제공하는 REST API를 개발할 때 주로 사용하며 객체를 ResponseEntity로 감싸서 반환한다.
ResponseEntity
- ResponseEntity를 사용하면 header, body, HTTP.status의 정보를 가져올 수 있다.
- body는 json타입으로 넘겨준다.
@PathVariable
- restful 서비스의 url 형태이다.
- 클라이언트에서 URL에 파라미터를 전달하는 url에서 각 구분자에 들어오는 값을 처리해야 할 때 사용한다.
- http://0.0.0.1/index/1 (restful 서비스의 url 형태 ) 와 같이 Rest api에서 값을 호출할 때 사용한다.
@PathVariable 사용법
@RequsetMapping의 URL 정의 & Method내의 파라미터 부분에 정의
- @RequestMapping 어노테이션 값으로 {템플릿 변수} 설정
- @PathVariable 어노테이션으로 {템플릿변수}와 동일한 이름을 가지는 파라미터를 추가.
-> RequestMapping에 있는 변수는 PathVariable 의 동일한 이름의 파라미터에 매핑된다.
exception 처리
@ExceptionHandler 를 사용해 custom exception 를 구현하여 예외를 처리한다.
@ExceptionHandler
- Controller계층에서 발생하는 에러를 잡아서 메서드로 처리해주는 기능이다.
Service, Repository에서 발생하는 에러는 제외한다.
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse>
handleUserNotFoundException(HttpServletRequest req, UserNotFoundException ex){
String requestURL = req.getRequestURI().toString();
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setRequestURL(requestURL);
errorResponse.setErrorCode("user.notfound.exception");
errorResponse.setErrorMsg("User with id " + ex.getUserId()+" not found");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND); // errorResponse가 body에 json형태로
}
@ExceptionHandler(UserDuplicatedException.class)
public ResponseEntity<ErrorResponse>
handleUserDuplicatedException(HttpServletRequest req, UserDuplicatedException ex){
String requestURL = req.getRequestURI().toString();
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setRequestURL(requestURL);
errorResponse.setErrorCode("user.duplicated.exception");
errorResponse.setErrorMsg("Unable to create. A user with name " + ex.getUsername() + " already exist ");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.CONFLICT); // CONFLICT : 이미 존재
}
REST Api 테스트
- Client Program인 Postman사용 하여 테스트 진행
REST API의 HTTP Method
HTTP Method | URI | Operation |
GET | /api/users | users 리스트를 반환한다 |
GET | /api/users/1 | ID가 1인 user를 반환한다 |
POST | /api/users | 새로운 user를 생성한다 |
PUT | /api/users/3 | ID가 3인 user를 업데이트한다 |
DELETE | /api/users/4 | ID가 4인 user를 삭제한다 |
DELETE | /api/users | 모든 users를 삭제한다 |
GET
- user객체를 json포멧으로 컨버팅하여 response message 의 body에 담아 보낸다.
- user의 내용이 json포맷으로 컨버팅 되어 보여지는 모습이다.
존재하지 않는 ID일 경우
- usernotfoundexception 발생
- 이에대한 handler인 usernotfoundhandler에의해 errorResponse에 내용이 담겨져 응답이 온다.
POST
requestmessage의 body부분에 raw에서 만들 사용자의 정보를 넣어준다.
이미 존재하는 user를 만들 경우
- userduplicatedexception 발생. body에 json형태로 errorrequest가 날아온다.
정상적으로 create가 이루어졌을 경우 id가 5인user가 생성됨을 알 수 있다.
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/api/users/{id}").buildAndExpand(user.getId()).toUri());
header의 location에서 설정해준 내용이 나타난다.
DELETE
없는 사용자를 제거할 경우 404 Not Found
성공적 제거 204 No Content
return new ResponseEntity<User>( HttpStatus.NO_CONTENT);
request를 보냈을때 response를 확인 할 수 있다.
+ 추가
ControllerAdvice를 사용한 예외처리 통합
exception handler가 특정 controller 안의 method에 의해서만 실행되지 않고, 모든 controller에 적용되도록 설정한다.
@ControllerAdvice
public class GlobalExceptionController {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse>
handleUserNotFoundException(HttpServletRequest req, UserNotFoundException ex){
String requestURL = req.getRequestURI().toString();
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setRequestURL(requestURL);
errorResponse.setErrorCode("user.notfound.exception");
errorResponse.setErrorMsg("User with id " + ex.getUserId()+" not found");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND); // errorResponse가 body에 json형태로
}
@ExceptionHandler(UserDuplicatedException.class)
public ResponseEntity<ErrorResponse>
handleUserDuplicatedException(HttpServletRequest req, UserDuplicatedException ex){
String requestURL = req.getRequestURI().toString();
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setRequestURL(requestURL);
errorResponse.setErrorCode("user.duplicated.exception");
errorResponse.setErrorMsg("Unable to create. A user with name " +
ex.getUsername() + " already exist ");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.CONFLICT); // 이미 존재
}
}
@ControllerAdvice
- exception을 다른 controller에서 hander를 사용할 수 있도록 한다.
- 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다.
[Spring] @Controller와 @RestController 차이 - MangKyu's Diary (tistory.com)
'Study > REST API' 카테고리의 다른 글
[REST API] REST API 이해하기 (0) | 2022.08.07 |
---|