RestApi ๋ง๋ค๊ธฐ - API์ธ๋ฑ์ค ์ง์ ๋ง๋ค๊ธฐ (8)
- ๊ฐ๋ฐ/restAPI๐ข
- 2021. 3. 3. 22:46

* ์ฌ๊ธฐ์ ์ธ๋ฑ์ค๋?
๋ฉ์ธ ํ์ด์ง๋ฅผ ๋ปํฉ๋๋ค.
๋ฉ์ธํ์ด์ง๋ฅผ ์ํ ํ
์คํธ ์ฝ๋๋ฅผ ์์ฑํ์.
@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์๊ฐ ๋๊ฒ ํ๋ค ใ
;
'๊ฐ๋ฐ > restAPI๐ข' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| RestApi ๋ง๋ค๊ธฐ - ์ด๋ฒคํธ ์กฐํ API๊ตฌํ (10) (0) | 2021.03.09 |
|---|---|
| RestApi ๋ง๋ค๊ธฐ - ์ด๋ฒคํธ ๋ชฉ๋ก ์กฐํ API๊ตฌํ (9) (0) | 2021.03.06 |
| RestApi ๋ง๋ค๊ธฐ - ๊ฐ์ข ๋ฌธ์ ์กฐ๊ฐ ์์ฑํ๊ธฐ(6) (0) | 2021.02.24 |
| RestApi ๋ง๋ค๊ธฐ - spring-rest-docs (5) (0) | 2021.02.19 |
| RestApi ๋ง๋ค๊ธฐ - HATEOAS (5) (0) | 2021.02.16 |