๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
TIL

REST API ์—์„œ์˜ HTTP ์‘๋‹ต ์ฝ”๋“œ (HTTP 201 Created)

by bamDal 2025. 2. 18.

 

๋ง‰์—ฐํ•˜๊ฒŒ ์•Œ๊ณ , ๋Œ€์ถฉ ์‚ฌ์šฉํ•˜๋˜ HTTP ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌํ•  ์‹œ๊ฐ„.. ๋“œ๋””์–ด..

ํ•œ ๋ฒˆ์— ํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ POST ํ•˜๋‚˜ ์ •๋ฆฌ๋„ ๊ฝค๋‚˜ ๊ฑธ๋ ค์„œ ๋‚˜๋ˆ ์„œ ์ •๋ฆฌํ•ด์•ผ๊ฒ ๋‹ค. ์‚ฌ์‹ค ์•„์ง POST ๋ง๊ณ ๋Š” ๊ถ๊ธˆํ•œ ์ ์ด ์—†์Œ.

 

< REST API์—์„œ์˜ HTTP ์‘๋‹ต ์ฝ”๋“œ >

  • ์กฐํšŒ(GET) => 200 OK
  • ์ƒ์„ฑ(POST) => 201 Created
  • ์ˆ˜์ •(PUT, PATCH) => 200 OK / 204 No Content
  • ์‚ญ์ œ(DELETE) => 204 No Content

 


๐Ÿ”ถ ์ƒ์„ฑ(POST)

POST ์š”์ฒญ ์‹œ 201 Created ์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค.
์ด ๋•Œ, Location ํ—ค๋”์— ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค์˜ URI๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

 

HTTP 201 Created

  • ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์—ˆ์œผ๋ฉฐ, ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

 

URI๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ณด๋‚ด๋Š” ์ฝ”๋“œ

    @PostMapping()
    public ResponseEntity<CommonResponse<MenuResponseDto>> createMenu(
        @RequestBody @Validated CreateMenuRequestDto requestDto) {
        MenuResponseDto responseDto = menuService.createMenu(requestDto);
        // URI ์ƒ์„ฑ
        URI location = ServletUriComponentsBuilder.fromCurrentContextPath()
            .path("/api/menus/" + responseDto.getRmId().toString())
            .build()
            .toUri();
        // Location์— ๋‹ด์•„์„œ ๋ณด๋‚ด๊ธฐ
        return ResponseEntity.created(location)
            .body(new CommonResponse<>(SuccessCode.MENU_CREATE, responseDto));
    }

 

< HTTP 201 Created ์‘๋‹ต์— URI๋ฅผ ํฌํ•จํ•˜๋Š” ์ด์œ  >

  1. HTTP 201 Created ์‘๋‹ต ํ‘œ์ค€์— ๋”ฐ๋ฅด๋ฉด Location ํ—ค๋”์— ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค์˜ URL์„ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ด ๊ทœ์น™์ด๋‹ค.
  2. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒํ•˜๋„๋ก ํ•œ๋‹ค.

 

 1. HTTP 201 Created ์‘๋‹ต ํ‘œ์ค€                            

HTTP 201์— ๋Œ€ํ•ด์„œ ๋‹จ์ˆœํ•˜๊ฒŒ Location ํ—ค๋”์— ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค URI๋ฅผ ํฌํ•จํ•ด์„œ ๋ณด๋‚ด์ž! ๋กœ ๋๋‚˜๋ฉด ์ข‹๊ฒ ๋‹ค.
๊ทผ๋ฐ ์™œ ํฌํ•จํ•ด์„œ ๋ณด๋‚ด์•ผํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•จ.. ์ด์œ  ์ฐพ๋‹ค๊ฐ€ ๋จธ๋ฆฌ๋งŒ ๋” ๋ณต์žกํ•ด์ง€๊ธด ํ–ˆ๋‹ค.
์˜์–ด๋กœ ์ฝ์–ด๋„, ํ•œ๊ตญ์–ด๋กœ ์ฝ์–ด๋„ ์ดํ•ด๊ฐ€ ์•ˆ๊ฐ€์„œ AI์˜ ํž˜์„ ๋นŒ๋ ธ๋‹ค.

๐Ÿ“Œ ์‰ฝ๊ฒŒ ๋ฒˆ์—ญํ•˜๋ฉด:
์š”์ฒญ์„ ํ†ตํ•ด ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ฃผ์š” ๋ฆฌ์†Œ์Šค(๋ฐ์ดํ„ฐ)๋Š” ์‘๋‹ต์˜ Location ํ—ค๋” ํ•„๋“œ์— ์žˆ๋Š” ์ฃผ์†Œ(URL) ๋กœ ์‹๋ณ„๋ฉ๋‹ˆ๋‹ค.
๋งŒ์•ฝ Location ํ—ค๋” ํ•„๋“œ๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์š”์ฒญ์„ ๋ณด๋‚ธ ์›๋ž˜์˜ ์ฃผ์†Œ(URI) ๊ฐ€ ์ƒˆ ๋ฆฌ์†Œ์Šค๋ฅผ ์‹๋ณ„ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

Location ํ—ค๋” ํ•„๋“œ์— ์ฃผ์†Œ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๊ฑธ ์ž์›์˜ ์ฃผ์†Œ๋กœ ์ธ์‹ํ•˜๋Š” ๊ฑด ์•Œ๊ฒ ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ, ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ์›๋ž˜ ์ฃผ์†Œ๋ฅผ ์ž์›์˜ ์ฃผ์†Œ๋กœ ์ธ์‹ํ•˜๋Š” ๊ฑธ๊นŒ? ๋ฐ˜๋“œ์‹œ ์ธ์‹์„ ํ•ด์•ผํ•˜๋Š”๊ฑด๊ฐ€?

โš ๏ธ 1. ์™œ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค์˜ ์ฃผ์†Œ๋ฅผ ๋ณด๋‚ด์•ผ ํ•˜๋Š”๊ฐ€?

=> RESTful API์˜ ๊ธฐ๋ณธ ์›์น™
REST API์—์„œ๋Š” ๋ฆฌ์†Œ์Šค๊ฐ€ ํŠน์ •ํ•œ URL๋กœ ์‹๋ณ„๋˜์–ด์•ผ ํ•œ๋‹ค.
์ฆ‰, ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋””์— ์žˆ๋Š”์ง€(URL)๊ฐ€ ๋ช…ํ™•ํ•ด์•ผ ํ•œ๋‹ค.

 

โš ๏ธ 2. ์™œ Location ํ—ค๋”๊ฐ€ ์—†์„ ๋•Œ ์š”์ฒญํ•œ URL์ด ์ƒˆ ๋ฐ์ดํ„ฐ์˜ ์ฃผ์†Œ๊ฐ€ ๋˜๋Š” ๊ฑธ๊นŒ?

=> Location ํ—ค๋”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ๊ธฐ์กด ๋ฆฌ์†Œ์Šค๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๊ฑฐ๋‚˜ ๊ฐœ๋ณ„ URL์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์ผ ๊ฒƒ์ด๋‹ค.
(์˜ˆ. ํ”„๋กœํ•„ ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•œ๋‹ค๋ฉด ์ƒˆ๋กœ์šด ๊ฐœ๋ณ„ ๋ฆฌ์†Œ์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ธฐ์กด ํ”„๋กœํ•„์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๊ธฐ์กด ์š”์ฒญ๊ณผ ๊ฐ™์•„ ์ƒˆ๋กœ์šด ์ฃผ์†Œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.

์š”์ฒญ : POST /api/users/123/profile-picture
์กฐํšŒ : GET /api/users/123/profile-picture
์ด๋Ÿฐ ๊ฐœ๋…์ธ ๋“ฏํ•˜๋‹ค. ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹ค๋ฅผ ๋ฟ ๋ฆฌ์†Œ์Šค ์š”์ฒญ ์ฃผ์†Œ๋Š” ๊ฐ™๋‹ค?

โš ๏ธ 3. ๊ผญ ๊ทธ ์ฃผ์†Œ๋ฅผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š”๊ฑด๊ฐ€?

์ด ๋ถ€๋ถ„์€ ์•„์ง๋„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ฒ ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ทธ ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค api๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒƒ ์•„๋‹ˆ์—ˆ๋‚˜..?

์•„๋ฌดํŠผ
๋ชจ๋“  ๊ฒฝ์šฐ์— ์ฃผ์†Œ๋ฅผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค์— ์ง์ ‘ ์กฐํšŒํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ๋ณด๋‚ผ ํ•„์š”๊ฐ€ ์—†๋‹ค.

์ง€ํ”ผํ‹ฐ๊ฐ€ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด์คฌ๋‹ค.

1.
ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑ

1-1.
๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ๋ชจ๋“  ๋ฆฌ๋ทฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์™€์„œ ๊ทธ ์‘๋‹ต์—์„œ ๋ฐฉ๊ธˆ ์ƒ์„ฑํ•œ ๋ฆฌ๋ทฐ๋ฅผ ์ฐพ์•„์•ผ ํ•œ๋‹ค. (๊ทธ๋ ‡๊ฒ ๊ตฌ๋งŒ.. ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ์˜ id๋ฅผ ๋ชจ๋ฅด๋‹ˆ๊นŒ..?)

1-2. 
์„œ๋ฒ„๊ฐ€ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ์˜ URI๋ฅผ ํฌํ•จํ•˜์—ฌ ์ฃผ๋ฉด ๊ทธ URI๋กœ ๋ฐ”๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ!!

 

 2. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒ      

์ƒ์„ฑ๋˜๋Š” URI๋ฅผ ๋ณด๋ฉด ์™œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‰ฝ๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
์œ„์— ์ฝ”๋“œ๋กœ ์ƒ์„ฑ๋œ URI์˜ ์˜ˆ์‹œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

GET http://localhost:8080/api/menus/123e4567-e89b-12d3-a456-426614174000

๋ฐฉ๊ธˆ ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์กฐํšŒํ•˜๋Š” URI๊ฐ€ ํด๋ผ์ด์–ธํŠธํ•œํ…Œ ์™„์„ฑ๋œ ์ƒํƒœ๋กœ ์ „๋‹ฌ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—
๊ทธ๋Œ€๋กœ ์š”์ฒญํ•ด์„œ ๋ฐฉ๊ธˆ ์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
์ƒ์„ฑ๋œ ๋ฆฌ์†Œ์Šค์˜ id๋ฅผ ๋ณ„๋„๋กœ ํŒŒ์‹ฑํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์„ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

 


 

์ฐธ๊ณ 

https://www.rfc-editor.org/rfc/rfc9110#status.201