RESTful WebService (3) - RESTful Service 기능확장

박정민·2021년 3월 14일
0

RESTful

목록 보기
3/4

1. Validation

User Domain 유효성 추가

<UserDomain class>

@Size(min=2, message = "Name은 2글자 이상 입력해주세요.") 
private String name;

@Past
private Date joinDate;
  • UserDomain의 name과 joinDate변수에 유효성 검사 추가
    • @Size: name변수는 최소 2글자 이상이여야 하고, 유효성 실패 메세지를 따로 지정함
    • @Past: joinDate변수는 과거 시간만 사용해야 함

<UserController class>

@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user){}
  • @Valid: 유효성을 검사해야 하는 변수 앞에 선언

<CustomizeResponseEntityExceptionHandler class>

@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);
}
  • 유효성 검사에 실패했을때 예외 처리

  • ResponseEntityExceptionHandler클래스의 handleMethodArgumentNotValid 재정의


2. Filtering

Response 데이터 제어를 위한 Filtering

  • 중요한 정보를 client에게 노출하지 않기 위해

  • 특정 정보를 외부에 노출시키고 싶지 않을 때

(1)어노테이션으로 제어하는 Filtering 방벙

<UserDomain class> 수정

@Data
@AllArgsConstructor
@NoArgsConstructor 
@JsonIgnoreProperties(value={"password", "ssn"})
public class User {
    private Integer id;

    @Size(min=2, message="Name은 2글자 이상 입력해 주세요.") 
    private String name;

    @Past
    private Date joinDate;

    // @JsonIgnore 
    private String password;

    // @JsonIgnore
    private String ssn; 
}
  • @JSonIgnore
    • 노출하기 싫은 필드에 이 어노테이션을 선언하면 해당 필드가 client응답에 포함되지 않음

  • @JsonIgnoreProperties(value={"~"})
    • @JsonIgnore와 달리 클래스 블록에 선언
    • value값에 노출하기 싫은 필드명들 기입

(2)프로그래밍으로 제어하는 Filtering 방법

<UserDomain class> 수정

@Data
@AllArgsConstructor
@NoArgsConstructor 
@JsonFilter("UserInfo") //"UserInfo"라는 이름부여
public class User {
    private Integer id;

    @Size(min=2, message="Name은 2글자 이상 입력해 주세요.")
    private String name;

    @Past
    private Date joinDate;

    private String password;
    private String ssn;
}

<AdminUserController class> 추가

@RestController
@RequestMapping("/admin") 
public class AdminUserController {
    private UserDaoService service;

    public AdminUserController(UserDaoService service) {
        this.service = service;
    }
    
    @GetMapping("/users") // /admin/users
    public MappingJacksonValue retrieveAllUsers() {
        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;
    }

  
    @GetMapping("/users/{id}") // /admin/users/{id}
    public MappingJacksonValue retrieveUser(@PathVariable int id) {
        User user = service.findOne(id);

    
        if(user == null) {
            throw new UserNotFoundException(String.format("ID[%s] not found", 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;
    }
}



3. Version 관리

URI를 이용한 REST API Version 관리

<UserDomain version2 class> 추가

//UserV2 class
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonFilter("UserInfoV2")
public class UserV2 extends User { // User Domain 상속
    private String grade;
}

<AdminUserController> 수정

// GET /admin/users/1 -> /admin/v1/users/1
@GetMapping("/v1/users/{id}")
public MappingJacksonValue retrieveUserV1(@PathVariable int id) {
    User user = service.findOne(id);

    if(user == null) {
        throw new UserNotFoundException(String.format("ID[%s] not found", 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;
}

// /admin/v2/users/1
@GetMapping("/v2/users/{id}")
public MappingJacksonValue retrieveUserV2(@PathVariable int id) {
    User user = service.findOne(id);

    if(user == null) {
        throw new UserNotFoundException(String.format("ID[%s] not found", id));
    }

    UserV2 userV2 = new UserV2();
    BeanUtils.copyProperties(user, userV2); // BeanUtils: Bean들간의 작업을 도와주는 class, user를 userV2로 복사
    userV2.setGrade("VIP"); 

    SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
            .filterOutAllExcept("id", "name", "joinDate", "grade");

    FilterProvider filters = new SimpleFilterProvider().addFilter("UserInfoV2", filter); 

    MappingJacksonValue mapping = new MappingJacksonValue(userV2);
    mapping.setFilters(filters);

    return mapping;
}
  • version1과 version2를 URI를 통해 구분하여 관리
    • version1 URI : /admin/v1/users/1
    • version2 URI : /admin/v2/users/1

Request Parameter와 Header를 이용한 API Version 관리

<AdminUserController> 수정

(1) Request Parameter 이용

//@GetMapping("/v1/users/{id}") //URI
@GetMapping(value = "/users/{id}/", params = "version=1") //parameter
public MappingJacksonValue retrieveUserV1(@PathVariable int id){}
  • Client 요청 방법: Get admin/users/1/?version=1

(2) Request Header 이용

//@GetMapping("/v1/users/{id}") //URI
@GetMapping(value = "/users/{id}", headers="X-API-VERSION=1") //header
public MappingJacksonValue retrieveUserV1(@PathVariable int id){}
  • Client 요청 방법: Get admin/users/1, Request Header에 Key: X-API-VERSION, Value: 1 입력

(3) MIME타입 이용

//@GetMapping("/v1/users/{id}") //URI
@GetMapping(value = "/users/{id}", produces = "application/vnd.company.appv1+json")
public MappingJacksonValue retrieveUserV1(@PathVariable int id){}
  • Client 요청 방법: Get admin/users/1, Request Header에 Key: Accept, Value: application/vnd.company.appv1+json 입력

  • 정리
    • version관리 방법
      • URI, Parameter를 통한 버전 관리: 일반 브라우저에서 실행 가능
      • Header, MIME 타입 통한 버전 관리: 일반 브라우저에서 실행 불가능
profile
화이팅!

0개의 댓글