일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 옵저버 패턴
- removeAll
- 전략 패턴
- 팩토리패턴
- 스프링 컨테이너
- @Tranctional
- 네트워크
- 백준 2164
- 후위표기식
- SOLID원칙
- 참조형 반환타입
- 빈 타입 조회
- try-catch
- 포워드 프록시
- 자바의 면접
- 스프링
- k번째큰수
- 팩토리 패턴
- 스프링 싱글톤
- 리버스 프록시
- 싱글톤 패턴
- 참조형 매개변수
- mvvm패턴
- 쇠막대기
- Class Loader
- TCP/IP 4계층
- www.naver.com치면 발생하는일
- 기본형 매개변수
- 백준 1935
- 스프링 빈
- Today
- Total
스파이더 웹 개발
RESTful Service 기능 확장 본문
유효성 검사
기존의 생성해두었던 User 클래스의 validation을 설정해주었다
@Data
@AllArgsConstructor
public class User {
private Integer id;
@Size(min = 2,message = "이름은 2글자 이상이여야 합니다")
private String name;
@Past
private Date joinDate;
}
이름의 size를 2로 설정해주었기에, name의 요청이 1이므로 400번 에러가 발생하는것을 확인할 수 있다.
이제 Body에 예외 내용을 추가해보자
요청을 처리할 메서드의 매개변수의 @Valid 어노테이션을 붙여주고, 기존의 커스텀마이즈 한 예외 처리에 메서드를 추가해주면된다
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(),"Validation failed", ex.getBindingResult().toString());
return new ResponseEntity(exceptionResponse,HttpStatus.BAD_REQUEST);
}
Body에 메시지도 나오고, 상태코드도 400번대로 확인이 잘되었다.
다국어 처리
다국어 처리는 애플리케이션 전반에 걸쳐 적용되어야하기에, Main 클래스에 Bean을 등록해준다
@Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.KOREA);
return localeResolver;
}
SessionLocaleResolver는 실제로 많이 사용되는 LocaleResolver이다. 말 그대로 Session에 Locale 정보를 넣고 이를 통해 다국어를 처리해주는 역할을 한다고 보면 된다. 현재 기본 값을 한국어로 설정해주었다.
이후 application yml 파일이나, properties 파일에 다국어 파일명을 저장한다
spring:
messages:
basename: mesaages
해당 properties파일에는 메시지를 입력해주었다. (참고로 _en, _fr 는 국가 코드이다)
@GetMapping(path = "/hello-world-internationalized")
public String helloWorldInternationalized(@RequestHeader(name = "Accept-Language",required = false) Locale locale){
return messageSource.getMessage(message, null, locale);
}
@RequestHeader의 name 과 required 관련하여 name은 Header에 Accept-Language 헤더가 required = false 이니 포함되지 않았다면 디폴트 값인 한국어가 설정된다
클라이언트에 전달하는 정보를 제어하는 방법
비밀번호 혹은 주민번호 중요한데이터가 클라이언트에 바로 노출이되면 보안상의 위험이 있기 때문에 필드값을 그대로 노출하는 것이아닌 방법을 확인해보자
User 클래스에 @JsonIgnore를 추가하자
@JsonIgnore
private String password;
@JsonIgnore
private String ssn;
해당 어노테이션을 추가한것만으로도 비밀번호와 주민번호가 무시된것을 확인할 수있다
@JsonIgnoreProperties(value ={"password","ssn"} )
public class User {
클래스 선언부에 JsonIgnoreProperties(value={})로 대체할 수도 있다.
프로그래밍 방식으로 Filter방법을 살펴보자 - 개별 사용자
@JsonFilter("UserInfo")
public class User {
클래스 선언부에 @JsonFilter 어노테이션을 사용해주고 사용할 이름을 설정해준다
@GetMapping("/users/{id}")
public MappingJacksonValue retrieveUser(@PathVariable int id){
User user = service.findOne(id);
if(user==null){
throw new UserNotFoundException(String.format("ID[%s]가 없습니다",id));
}
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
.filterOutAllExcept("id", "name", "joinDate", "ssn");
FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfo",filter);
MappingJacksonValue mapping = new MappingJacksonValue(user);
mapping.setFilters(filters);
return mapping;
}
이후 적용할 컨트롤러에 메서드에 사용해주는데, filterOutAllExcept 메서드에 매개변수로는 Body에 보여질 User객체의 필드들을 적어준다. 이후 MappingJacksonValue 타입으로 반환해주어야하므로 FilterProvider를 통해 타입을 설정해주고 반환해주면된다
전체사용자 적용방법
@GetMapping("/users")
public MappingJacksonValue retrieveAllUser(){
List<User> users = service.findAll();
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
.filterOutAllExcept("id", "name", "joinDate", "ssn");
FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfo",filter);
MappingJacksonValue mapping = new MappingJacksonValue(users);
mapping.setFilters(filters);
return mapping;
}
URI를 이용한 버전 관리
@GetMapping("/v1/users/{id}")
public MappingJacksonValue retrieveUserV1(@PathVariable int id)
@GetMapping("/v2/users/{id}")
public MappingJacksonValue retrieveUserV2(@PathVariable int id)
이러한 방식으로 URI와 메서드의 이름을 달리하여 버전을 관리 해준다
또한 버전이 바뀌면서 메서드내의 도메인을 변경해주어야 하는 경우도 있는데 아래와같이
@Data
@AllArgsConstructor
@JsonFilter("UserInfoV2")
public class UserV2 extends User{
private String grade;
}
기존의 User를 상속받고, 필드를 추가해주었다 그리고 추가적으로 기존의 v1메서드에 User에 있는 데이터값을 User2로 전달해주어야하는데 BeanUtils.copyProperties를 통해 해결할 수 있다.
//User가 가지고있는 데이터 값을 -> User2에 전달
UserV2 userV2 = new UserV2();
BeanUtils.copyProperties(user, userV2);
userV2.setGrade("VIP");
Request Parameter와 Header를 이용한 API Version 관리
Request Parameter를 이용한 버전 관리
@GetMapping("/v1/users/{id}")
-> @GetMapping(value = "/users/{id}",params = "version=1")
@GetMapping("/v2/users/{id}")
-> @GetMapping(value = "/users/{id}",params = "version=2")
Header를 이용한 버전관리
@GetMapping(value = "/users/{id}",headers = "version=1")
'RESTful API' 카테고리의 다른 글
스프링 부트를 활용한 RESTful (0) | 2022.09.19 |
---|---|
HTTP Method 와 Exception Handling (0) | 2022.09.18 |
RESTFul 알아보기 (0) | 2022.09.18 |
REST/REST API /RESTFul API 란? (0) | 2022.09.18 |