๊ฐœ๋ฐœ/restAPI๐Ÿ˜ข

RestApi ๋งŒ๋“ค๊ธฐ - 201์ฝ”๋“œ ์ƒ์„ฑํ•˜๊ธฐ (1)

klom 2021. 1. 30. 18:35
๋ฐ˜์‘ํ˜•

๋‚˜๋Š” ๋ฐฐ๋‹ฌAPI๋ฅผ restAPI๋กœ ๋งŒ๋“ค์–ด ๋ณผ๋ ค๊ณ  ํ•œ๋‹ค.
๋‚ด์šฉ์€ ์Šคํ”„๋ง ๊ธฐ๋ฐ˜ REST API ๊ฐœ๋ฐœ ์—์„œ ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ์ฐธ์กฐํ•ด์„œ ๋งŒ๋“ค์—ˆ๋‹ค.

์›๋ž˜๋Š” restAPI์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ๋งํ•˜๊ณ  ์‹œ์ž‘ํ•ด์•ผ ๋˜์ง€๋งŒ 
์•„์ง์€ ์„ค๋ช…ํ•˜๊ธฐ๋Š” ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™๋‹ค,
์ผ๋ฐ˜์ ์ธ api๋ณด๋‹ค ์ƒํƒœ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑด ํ™•์‹คํ•˜๋‹ค.

์•„๋ฌดํŠผ api๋ฅผ ๋งŒ๋“ค๊ธฐ์œ„ํ•ด์„œ๋Š” dto๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ž๋ฐ”๋นˆ๊ฐ™์€๊ฒŒ  ํ•„์š”ํ•˜๋‹ค๋Š” ๋œป์ด๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ 

@Builder
@Setter @Getter
public class Delivery {
    private int id;
    private String item;
    private String user;
    private LocalDateTime deliveryTime;
    private DeliveryStatus status;
}

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ–ˆ๋‹ค.

์ด์ œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์ž.

๋‚˜๋Š” mockMVC๋ฅผ ์‚ฌ์šฉํ•ด์•ผ๋œ๋‹ค.
mockMVC๋Š” ์›น์œผ๋กœ ์ง์ ‘์ ์œผ๋กœ ํ†ต์‹ ํ•˜์ง€ ์•Š๊ณ , ๊ฐ€์ƒ์œผ๋กœ ์›น์œผ๋กœ ํ˜ธ์ถœ์ด ์ž˜ ๋˜์—ˆ์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
(mock์ด ๊ฐ€์งœ๋ผ๊ณ  ํ•˜์ง€๋งŒ ํ”„๋ก์‹œ๋„ ๊ฐ€์งœ๊ณ  ๊ทธ๋ž˜์„œ ๊ฐ€์งœ๋ผ๋Š” ๋ง์ด ์‹ซ๋‹ค.)

@WebMvcTest
class DeliveryTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void create_Delivery() throws Exception {
        mockMvc.perform(post("/api/delivery"))
               .andExpect(status().isCreated());
    }
}

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์ด๋ ‡๊ฒŒ ์ž์„ฑํ•˜์˜€๋‹ค.
ํฌ์ŠคํŠธ ๋ฐฉ์‹์œผ๋กœ ๋ณด๋‚ด๊ณ , url์ด ๋“ค์–ด์˜ค๋ฉด ์ƒ์„ฑํ•˜๋ผ๋Š” ๋œป์ด๋‹ค.

ํ•˜์ง€๋งŒ ์ด๊ฑด404์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋œ๋‹ค.

์™œ๋ƒํ•˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

@Controller
public class DeliveryController {
    
    @PostMapping("/api/delivery")
    public ResponseEntity createDelivery() {
        
        return ResponseEntity.created().build();
    }
}

ResponseEntity๋Š” ์‘๋‹ต์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ํ–‰์œ„๋ผ ์ƒ๊ฐ์ด ๋“ ๋‹ค.
๊ทผ๋ฐ created๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” uri๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

uri๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.


์›๋ž˜๋Š”

URI uri = URI.create("/api/delivery");

์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ๋˜์ง€๋งŒ... ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ์ ์ด
uri๊ฐ€ ๋ณ€๊ฒฝ์ด ๋œ๋‹ค๋ฉด ์ € uri๋ฅผ ์ˆ˜์ •ํ•ด๋˜๋Š” ๋ถˆ์ƒ์‚ฌ๊ฐ€ ๋ฐœ์ƒ๋  ์ˆ˜ ์žˆ๋‹ค.(์•„๋‹ ๊ฐ€๋Šฅ์„ฑ์ด ๋” ํฌ์ง€๋งŒ...ใ…Žใ…Ž)

spring hateoaus๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งํฌ๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 URI createUri = linkTo(DeliveryController.class).slash("{id}").toUri();

์œ„ ์ฝ”๋“œ๋Š” ์œ„์—์„œ ์ž‘์„ฑ๋œ uri์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

๊ทผ๋ฐ ๋‚ด๊ฐ€ ๊ธฐ๋Œ€ํ•œ uri๋ž‘ ๋‹ค๋ฅธ ์ •๋ณด๊ฐ€ ๋‚˜์™”๋‹ค.
์™œ๋ƒํ•˜๋ฉด ๋‚˜๋Š” ํด๋ž˜์Šค์— ์ •์˜๋œ ๋งคํ•‘๊ฐ’์„ ๊ฐ€์ ธ์™”๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์ด๊ฑธ ๋ฉ”์†Œ๋“œ๋กœ ๋ฐ”๊ฟ”์ค˜์•ผ ๋œ๋‹ค.

URI createUri = linkTo(methodOn(DeliveryController.class).createDelivery()).slash("{id}").toUri();

์ด์ œ delivery์ •๋ณด๋ฅผ ๋„˜๊ฒจ์„œ ๊ทธ์•ˆ์— ์ •๋ณด๋“ค์„ ๋„ฃ์–ด๋ณด์ž.
๊ทผ๋ฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

๋ฉ”์†Œ๋“œ๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„ฃ์–ด์ค˜์•ผ ํ–ˆ๋‹ค. 
์—ฌ๊ธฐ์„œ 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•œ๋‹ค.

์ €๊ณณ์— null์„ ๋„ฃ๋˜์ง€,
์•„๋‹ˆ๋ฉด, ํด๋ž˜์Šค์— ์ •์˜ ํ•˜๋˜์ง€ ๊ฒฐ์ •ํ•ด์•ผ๋œ๋‹ค.

๋‚˜๋Š” ํด๋ž˜์Šค์— ์ •์˜ํ•˜๋Š” ๋ฐฉ์‹์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ๋ณ€๊ฒฝํ•˜๊ณ  ๋‹ค์‹œ ์ƒํ–‰ํ•ด์ฃผ์—ˆ๋”๋‹ˆ,

์ด๋Ÿฐ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

๊ตฌ๊ธ€์˜ ํž˜์„ ๋นŒ๋ฆฐ ๊ฒฐ๊ณผ ์ด๊ฑด 500์—๋Ÿฌ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.
๊ทธ๋ ‡๋‹ค๋Š”๊ฑด ๊ฐ’์ด ์ ์ ˆํ•˜๊ฒŒ ๋“ค์–ด๊ฐ€์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ธ๊ฐ€?
ํ™•์ธ ๊ฒฐ๊ณผ,
๋‚ด๊ฐ€ ๋งŒ๋“  dto์— ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.
๋นŒ๋”๋กœ ๋งŒ๋“ค๊ฒŒ ๋˜๋ฉด ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋„ฃ์–ด์•ผ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ์ด๊ฒƒ์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋นˆ ์ƒ์„ฑ์ž๋„ ํ•„์š”ํ•˜๋‹ค.
๊ทธ๋Ÿฌ๋ฉด @NoArgsConstructor๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ ๊นŒ?

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค๊ฒŒ ๋˜๋ฉด ๋”์ด์ƒ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋„ฃ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋นŒ๋”์˜ ์—ญํ• ์€ ์—†์–ด์ง„๋‹ค.
๊ทธ๋ž˜์„œ

@Builder
@Setter @Getter
@NoArgsConstructor
@AllArgsConstructor
public class Delivery {

์ •์ƒ์ ์œผ๋กœ ๋‚˜์™”๋‹ค.

์›๋ž˜ header์—๋„ ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š”๊ฒŒ ์ข‹์ง€๋งŒ, ๊ทธ๋ƒฅ ๊ฐ„๋‹จํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ ‡๊ฒŒ ํ–ˆ๋‹ค.ใ…Ž;