RestApi 만들기 - API인덱스 지점 만들기 (8)

반응형
반응형

* 여기서 인덱스란?
메인 페이지를 뜻합니다.
메인페이지를 위한 테스트 코드를 작성하자.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@Import(RestDocsConfiguration.class)
@ActiveProfiles("test")
public class IndexControllerTest {

  @Autowired
  private MockMvc mockMvc;

  @Test
  void index() throws Exception {
    mockMvc.perform(get("/delivery"))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("_links.delivery").exists());
  }

}

코드가 DeliveryTest와 중복된 부분이 보이지만...
일단 그대로 진행하였다.(사실 모름)
아무튼
테스트 코드는
get으로 요청을 보내고 그것을 프린트하구
상태값이 200인지 확인하자.
마지막으로 위 링크가 존재하는지 확인한다.

테스트 결과는

당연히 404가 나왔다.

나는 IndexController를 만들지 않았기 때문에
그곳부터 만들자.

@Controller
public class IndexController {

  @GetMapping("/delivery")
  public ResponseEntity<?> index() {
    return ResponseEntity.ok().build();
  }

}

이렇게 만들면 잘 될까?
생각해본다.

이번에는 link가 없다고 한다.

다시 

  • ResourceSupport => RepresentationModel

  • Resource => EntityModel

  • Resources => CollectionModel

  • PagedResources => PagedMode

이것을 복습해보자.
RepresentationModel를 이용해서 리소스를 만들 수 있다.
pagedMode는 되지 않고, 나머지 두개는 상속일때만 가능하다.
그러면 다음과 같은 코드를 작성할 수 있다.

public ResponseEntity<?> index() {
    var resource = new RepresentationModel<>();
    resource.add(linkTo(IndexController.class).withRel("delivery"));
    return ResponseEntity.ok().body(resource);
  }

build에서 body로 바꾼이유는 리소스를 저장하기 위함이다.
실행을 시키면..

정상적으로 동작된다는 것을 알 수 있다.

그러면 이것은 언제 사용이 되어질까?
생각해보면 에러페이지에서 사용되어진다.

어딘지는 모르겠으나. 이런식으로 에러가 발생하면 메인페이지로 이동하게 되어있다.
그래서 우리도 에러페이지에 추가해보자.

@Test
  void badRequest_wrong_input() throws Exception {
    DeliveryDto delivery = DeliveryDto.builder()
        .item("book")
        .user("klom")
        .deliveryEndTime(LocalDateTime.now())
        .deliveryTime(LocalDateTime.now().plusDays(10))
        .itemPrice(0)
        .build();

    mockMvc.perform(post("/api/delivery/")
        .contentType(MediaType.APPLICATION_JSON_VALUE)
        .content(objectMapper.writeValueAsString(delivery))
    )
        .andDo(print())
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.[0].objectName").exists())
        .andExpect(jsonPath("$.[0].field").exists())
        .andExpect(jsonPath("$.[0].rejectedValue").exists())
        .andExpect(jsonPath("$.[0].links.index").exists())
    ;
  }

잘못된 링크에 들어가게 되면 이 링크가 실행되게 만들었다.
이걸 실행해보면.

 인덱스가 존재하지 않는다고 나온다.

그 이유는

if (errors.hasErrors()) {
   return ResponseEntity.badRequest().body(errors);
}

이거 때문이다.
이것을 해결하기 위해서는 리소스 즉 링크 정보를 넣어줘야 된다.
그 정보를 만들어보자.
마침

public class DeliveryModel extends EntityModel<Delivery> {
  public DeliveryModel(Delivery delivery, Link... links) {
    super(delivery, links);
    add(linkTo(DeliveryController.class).withRel("query-events"));
    add(linkTo(DeliveryController.class).slash(delivery.getId()).withRel("update-events"));
    add(linkTo(DeliveryController.class).slash(delivery.getId()).withSelfRel());
    add(Link.of("http://localhost:8080/docs/index.html#resources-index").withRel("profile"));
  }
}

이렇게 만든게 있어서 이것을 참고해서 만들면 될것 같다.

public class ErrorModel extends EntityModel<Errors> {

  public ErrorModel(Errors content, Link... links) {
    super(content, links);
    add(linkTo(methodOn(IndexController.class).index()).withRel("index"));
  }
}

만든뒤,

 if (errors.hasErrors()) {
     return ResponseEntity.badRequest().body(new ErrorModel(errors));
}

이렇게 만들면 된다.
만약 중복된게 존재하면 리펙토링해서 변경시켜줘도 된다.
그건 알아서...
문제가 발생했다.

이런 오류가 발생했는데..
이유를 확인해보니 오브젝트로 시작할 수 없다.
필드 이름을 넣어야 된다라고 나와 있다.

스프링2.3이 넘어오면서 배열로 만드는 것을 허용하지 않는다고 한다.

 

[인덱스 만들기] 에서 ErrorsResource 부분 질문입니다. - 인프런 | 질문 & 답변

좋은 질문 감사합니다. 스프링 부트 2.3으로 올라가면서 Jackson 라이브러리가 더이상 Array부터 만드는걸 허용하지 않습니다. 2020-10-02 22:09:06.151  WARN 14548 --- [           main] .w.s.m.s.DefaultHandlerExcep

www.inflearn.com

그래서 

jsonGenerator.writeFieldName("errors");
jsonGenerator.writeStartArray();

이런식으로 추가하구.

.andExpect(jsonPath("errors[0].objectName").exists())
.andExpect(jsonPath("errors[0].field").exists())
.andExpect(jsonPath("errors[0].rejectedValue").exists())
.andExpect(jsonPath("_links.index").exists())

테스트 코드를 이렇게 수정했다.
그리고 실행시켜보자.

잘 나온다.
겸사겸사

public static EntityModel<Errors> modelOf(Errors errors) {
    EntityModel<Errors> errorsModel = EntityModel.of(errors);
    errorsModel.add(linkTo(methodOn(IndexController.class).index()).withRel("index"));
    return errorsModel;
  }

이 코드도 수정시켜줬다.
강의는 13분짜리지만... 이걸 1시간 넘게 했네 ㅎ;

반응형

댓글

Designed by JB FACTORY