[rest api 프로젝트 구축] - bad request 처리

geun kim·2023년 3월 24일
0

REST API 구축

목록 보기
4/20

1. json으로 binding 될 객체보다 더 많은 프로퍼티가 들어 올 때 Bad Reqeust 에러처리 방법

desirialization : json -> 객체로 변환
serialization : 객체 -> json으로 변환

입력값으로 객체보다 추가적인 데이터까지 같이 주면?
○ Bad_Request로 응답 vs 받기로 한 값 이외는 무시

아래 옵션을 사용 할 지는 좀 더 생각 해 보자.

#application.properties
#ObjectMapper 커스터마이징
#desirialization 할 때 binding 할 프로퍼티가 존재 하지 않으면 실패 처리
#Bad Request 처리 시 사용
spring.jackson.deserialization.fail-on-unknown-properties=true

2. 필수 입력값 및 길이 제한 등 유효성 검증 방법

@Valid와 BindingResult (또는 Errors)
● BindingResult는 항상 @Valid 바로 다음 인자로 사용해야 함. (스프링 MVC)
● @NotNull, @NotEmpty, @Min, @Max, ... 사용해서 입력값 바인딩할 때 에러 확인할
수 있음

handler method 구현

@Valid EventDto eventDto // dto 객체를 검증한다.

// 에러 확인 후 존재하면 에러 코드를 돌려준다.
if(errors.hasErrors()){
return ResponseEntity.badRequest().build();
}

@PostMapping
    public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto , Errors errors) {
        // 에러 확인 후 존재하면 에러 코드를 돌려준다.
        if(errors.hasErrors()){
            return ResponseEntity.badRequest().build();
        }

        /**
         * modelmapper를 이용해서 dto의 값을 domain객체에 값 복사 해 준다.
         */
        Event event = modelMapper.map(eventDto,Event.class);
        Event newEvent = eventRepository.save(event);
        URI uri = linkTo(EventContoller.class).slash(newEvent.getId()).toUri();
        return ResponseEntity.created(uri).body(event); // ResponseEntity를 사용하여 header 정보 등록
    }

DTO 객체에 validation 관련 어노테이션 선언


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventDto {
    @NotEmpty
    private String name;
    @NotEmpty
    private String description;
    @NotNull
    private LocalDateTime beginEnrollmentDateTime;
    @NotNull
    private LocalDateTime closeEnrollmentDateTime;
    @NotNull
    private LocalDateTime beginEventDateTime;
    @NotNull
    private LocalDateTime endEventDateTime;
    private String location; // (optional) 이게 없으면 온라인 모임
    @Min(0)
    private int basePrice; // (optional)
    @Min(0)
    private int maxPrice; // (optional)
    @Min(0)
    private int limitOfEnrollment;
}

3. 입력값 검증

도메인 Validator 만들기

@Component
public class EventValidator {

    public void validate(EventDto eventDto, Errors errors) {
        if (eventDto.getBasePrice() > eventDto.getMaxPrice() && eventDto.getMaxPrice() > 0) {
            errors.reject("wrongPrices", "Values fo prices are wrong");
        }

        LocalDateTime endEventDateTime = eventDto.getEndEventDateTime();
        if (endEventDateTime.isBefore(eventDto.getBeginEventDateTime()) ||
        endEventDateTime.isBefore(eventDto.getCloseEnrollmentDateTime()) ||
        endEventDateTime.isBefore(eventDto.getBeginEnrollmentDateTime())) {
            errors.rejectValue("endEventDateTime", "wrongValue", "endEventDateTime is wrong");
        }

        // TODO BeginEventDateTime
        // TODO CloseEnrollmentDateTime
    }

}

validator 활용

  @PostMapping
    public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto , Errors errors) {
        // 1.binding 할 때 에러가 존재 확인
        // 에러 확인 후 존재하면 에러 코드를 돌려준다.
        if(errors.hasErrors()){
            return ResponseEntity.badRequest().build();
        }

        //2.입력값 검증 , eventValidator 로직 검증
        eventValidator.validate(eventDto,errors);

        //3.에러 확인 후 존재하면 에러 코드를 돌려준다.
        if(errors.hasErrors()){
            return ResponseEntity.badRequest().build();
        }


        /**
         * modelmapper를 이용해서 dto의 값을 domain객체에 값 복사 해 준다.
         */
        Event event = modelMapper.map(eventDto,Event.class);
        Event newEvent = eventRepository.save(event);
        URI uri = linkTo(EventContoller.class).slash(newEvent.getId()).toUri();
        return ResponseEntity.created(uri).body(event); // ResponseEntity를 사용하여 header 정보 등록
    }

결론

2,3번을 활용하여 입력값 유효성 검증을 하면 되겠다.

1번 추가적인 필드값들은 유연하게 넘어가는 것이 좋을 듯 하다........

[공부 및 조사가 필요하다]

handler에서 변수 binding할 객체는 map에 담는지

DTO에 담아서 처리하는 지 확인 해 보자.....

map 담으면 2,3번은 사용 할 수 없는데.....

profile
Devops Load Map

0개의 댓글