Dev_articles/Backend

[API 섀계] DELETE request μš”μ²­/처리/응닡에 κ΄€ν•œ μ†Œμ†Œν•œ κ³ λ―Ό

humblEgo 2021. 4. 26. 20:46

πŸ‘¨πŸ»‍πŸ’» λ“€μ–΄κ°€λ©°

졜근 μ œν•œλœ μ‹œκ°„ μ•ˆμ— RESTful APIλ₯Ό μ„€κ³„ν•˜κ³  κ΅¬ν˜„ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. κ·Έ 와쀑에 아직 잘 μˆ™μ§€κ°€ λ˜μ§€ μ•Šμ•˜λŠ”μ§€ λ¬˜ν•˜κ²Œ μœ„ν™”κ°μ΄ μžˆλŠ” 뢀뢄이 μžˆμ—ˆλŠ”λ°μš”, λ°”λ‘œ DELETE μš”μ²­ λ©”μ„œλ“œμ˜ 처리 μ •μ±…μž…λ‹ˆλ‹€.

λ‹¨μˆœνžˆ 예제 μˆ˜μ€€μ—μ„œ DELETE μš”μ²­ λ©”μ„œλ“œλ‘œ μžμ› μ‚­μ œλ₯Ό μš”μ²­ν•˜λŠ” 것은 정말 μ‰½μ§€λ§Œ, μ•„λž˜ μƒν™©μ—μ„œ κ³ λ―Όλ˜λŠ” 지점듀이 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

  • DELETE μš”μ²­ν•œ ν΄λΌμ΄μ–ΈνŠΈμ˜ κΆŒν•œμ„ κ²€μ‚¬ν•΄μ•Όν•˜λŠ” μƒν™©μ—μ„œ, 인증/인가에 ν•„μš”ν•œ 정보λ₯Ό 어디에 λ‹΄μ•„μ„œ μš”μ²­ν•΄μ•Όν• κΉŒ?
  • Soft delete ν•˜λŠ” μƒν™©μ—μ„œ soft delete μ—¬λΆ€λ₯Ό κ΄€λ¦¬ν•˜λŠ” 컬럼 이름은 무엇이 μ μ ˆν• κΉŒ?
  • 그리고 μžμ›μ„ μ‚­μ œν•˜λŠ” 것이 μ•„λ‹ˆλΌ ν”Œλž˜κ·Έλ₯Ό λ°”κΎΈλŠ” κ²ƒμ΄λ‹ˆ λ©”μ„œλ“œλŠ” PATCH λ©”μ„œλ“œλ₯Ό μ¨μ•Όν•˜λŠ” 걸까?
  • DELETE μš”μ²­μ— λŒ€ν•΄ μ‘λ‹΅ν•΄μ•Όν•˜λŠ” μƒν™©μ—μ„œ μ–΄λ–€ 값을 λ¦¬ν„΄ν•΄μ•Όν• κΉŒ?

κ³ λ―Όν•œ λ‚΄μš©μ„ DELETE μš”μ²­ λ©”μ„œλ“œλ₯Ό μ²˜λ¦¬ν•˜λŠ” 과정을 μš”μ²­, μ‹€ν–‰, μ‘λ‹΅μœΌλ‘œ λ‚˜λˆ μ„œ κ³΅μœ ν•©λ‹ˆλ‹€.

πŸ”œ μš”μ²­

보톡 RESTful APIμ—μ„œλŠ” λ™μΌν•œ μžμ›μ— λŒ€ν•΄ CRUD μš”μ²­μ„ ν•˜λ”λΌλ„, μš”μ²­ν•œ ν΄λΌμ΄μ–ΈνŠΈμ˜ κΆŒν•œμ— 따라 λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λ„λ‘ κ΅¬ν˜„ν•  ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. DELETE μš”μ²­ λ©”μ„œλ“œλŠ” API 호좜 μ‹œ μžμ›μ— λ³€ν™”λ₯Ό μΌμœΌν‚¨λ‹€λŠ” μ μ—μ„œ 'λΉ„μ•ˆμ •μ„±'을 κ°€μ§€λ―€λ‘œ, κΆŒν•œ 검사가 λ”λ”μš± ν•„μˆ˜μž…λ‹ˆλ‹€.

κΆŒν•œ κ²€μ‚¬λŠ” μ–΄λ–»κ²Œ ν•  수 μžˆμ„κΉŒμš”? μ›Ή μ„œλΉ„μŠ€μ—μ„œ 주둜 μ“°μ΄λŠ” HTTP ν”„λ‘œν† μ½œμ€ 기본적으둜 μƒνƒœλ₯Ό μ €μž₯ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ(Stateless), DELETE μš”μ²­ 메세지에 ν΄λΌμ΄μ–ΈνŠΈλ₯Ό 인증/μΈκ°€ν•˜λŠ”λ° ν•„μš”ν•œ 정보λ₯Ό ν•¨κ»˜ 보낼 ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€.

그리고 이 정보λ₯Ό μš”μ²­ 메세지에 λ‹΄μ„λ§Œν•œ 곳으둜 3가지λ₯Ό κ³ λ €ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

URL query string parameter (λΉ„μΆ”μ²œ)

κ°„νŽΈν•˜μ§€λ§Œ λ³΄μ•ˆμƒ μ·¨μ•½ν•˜λ―€λ‘œ μΆ”μ²œν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ™„λ²½ν•œ λ³΄μ•ˆμ€ μ—†λ‹€μ§€λ§Œ "μ„  λ„˜λ„€..?" μ†Œλ¦¬κ°€ 절둜 λ‚˜μ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

  • 인증에 ν•„μš”ν•œ username, id, password λ“± 민감 정보가 κ·ΈλŒ€λ‘œ λ…ΈμΆœλ  수 μžˆμœΌλ―€λ‘œ λ³΄μ•ˆμƒ 쒋지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • λ˜ν•œ μ•„λž˜ μ΄μœ λ“€ λ•Œλ¬Έμ— HTTPSλ₯Ό μ‚¬μš©ν•˜λ”λΌλ„ μ—¬μ „νžˆ λ³΄μ•ˆμƒ 쒋지 μ•ŠμŠ΅λ‹ˆλ‹€!
    • server log에 passwordκ°€ ν‰λ¬ΈμœΌλ‘œ κ·ΈλŒ€λ‘œ μ €μž₯될 수 μžˆμŠ΅λ‹ˆλ‹€.
    • λΈŒλΌμš°μ € νžˆμŠ€ν† λ¦¬μ— URL이 μ €μž₯될 수 μžˆμŠ΅λ‹ˆλ‹€.
    • Google Analytics 같은 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— Referer ν—€λ”λ“€λ‘œ URL이 μ „λ‹¬λ˜λ©° 민감정보가 κ·ΈλŒ€λ‘œ λ“œλŸ¬λ‚  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

Request Body parameter (λΉ„μΆ”μ²œ)

A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request. - RFC 7231

Request body에 인증/인가 정보λ₯Ό λ„£λŠ” 것은 μ–΄λ–¨κΉŒμš”? URL query string parameter에 λΉ„ν•΄ URL에 직접 λ…ΈμΆœμ΄ λ˜μ§€ μ•ŠμœΌλ―€λ‘œ Query string λ°©μ‹λ³΄λ‹€λŠ” λ³΄μ•ˆμ΄ μ’‹λ‹€κ³  ν•  수 μžˆλŠ”λ°μš”(μ—¬μ „νžˆ μ•”ν˜Έν™”λŠ” ν•„μˆ˜μ§€λ§Œ), 이둀적인 λ°©μ‹μ΄λΌλŠ” μ μ—μ„œ μΆ”μ²œν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

  • DELETE μš”μ²­μ‹œ Request에 bodyλ₯Ό ν¬ν•¨μ‹œν‚€λŠ” 것이 κΈˆμ§€λ˜μ–΄ μžˆμ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€, ν•˜μ§€λ§Œ DELETE μš”μ²­ 메세지에 bodyκ°€ ν¬ν•¨λ˜μ–΄μžˆμœΌλ©΄ μš”μ²­μ„ κ±°μ ˆν•΄λ²„λ¦¬λŠ” μ„œλ²„κ°€ λ§ŽμŠ΅λ‹ˆλ‹€. 이둀적인 λ°©μ‹μœΌλ‘œ 받아듀여지고 μžˆλŠ” 것이죠.

λ³„κ°œλ‘œ ꡳ이 DELETE λ©”μ„œλ“œλ₯Ό 고집할 ν•„μš”κ°€ μ—†λ‹€λ©΄, Request body에 ν•„μš”ν•œ 정보λ₯Ό λ‹΄κ³ , POST λ©”μ„œλ“œ μš”μ²­ 메세지λ₯Ό λ³΄λ‚΄λŠ” 것도 λ‚˜μ˜μ§€ μ•Šμ€ λ°©λ²•μž…λ‹ˆλ‹€. DELETE λ©”μ„œλ“œ 자체λ₯Ό ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” μ„œλ²„, 방화벽이 λ§Žμ•„μ„œ νŽΈμ˜μ„± μΈ‘λ©΄μ—μ„œ 더 쒋을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ‹€μ œλ‘œ TOSS의 결제 μ‹œμŠ€ν…œμ˜ 경우, PG 연동 κ°œλ°œμžλ“€μ˜ 편의λ₯Ό μœ„ν•΄ POST λ©”μ„œλ“œλ‘œ DELETE μš”μ²­μ— ν•΄λ‹Ήν•˜λŠ” APIλ₯Ό λ””μžμΈν•œ 사둀가 μžˆμŠ΅λ‹ˆλ‹€. κ΄€λ ¨ λ‚΄μš©μ€ 이 링크에 μš”μ•½ν•΄λ’€μ–΄μš” :)

 

Request Header parameter (μΆ”μ²œ)

Request header에 값을 λ„£μ–΄μ„œ μš”μ²­ν•˜λŠ” 것을 μΆ”μ²œν•©λ‹ˆλ‹€. Query string보닀 λ³΄μ•ˆμ΄ μ¬λ”μ΄λ‚˜λ§ˆ μ’‹κ³ , Body parameter보닀 μ’€ 더 일반적인 λ°©λ²•μž…λ‹ˆλ‹€.

μ œκ°€ ν™•μΈν•œ Request headerλ₯Ό μ΄μš©ν•œ 방법 μ˜ˆμ‹œλŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • Authorization 헀더에 Bearer νƒ€μž…μ„ λͺ…μ‹œν•˜κ³ , 인증 정보가 λ‹΄κΈ΄ JWT 토큰을 λ„£μ–΄μ„œ λ³΄λ‚΄λŠ” 방법
  • Authorization 헀더에 Basic νƒ€μž…μ„ λͺ…μ‹œν•˜κ³ , username:password을 BASE64 μΈμ½”λ”©ν•΄μ„œ HTTPS둜 λ³΄λ‚΄λŠ” 방법. BASE64λŠ” μ‰½κ²Œ 디코딩이 κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— 별도 λ°©λ²•μœΌλ‘œ μ•”ν˜Έν™”ν•  ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€.

πŸ”› μ‹€ν–‰

ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ΄ μœ νš¨ν•˜λ‹€λ©΄, μžμ›μ„ hard delete 할지, soft delete 할지 선택해야 ν•©λ‹ˆλ‹€. 각자 μž₯단점이 μžˆμŠ΅λ‹ˆλ‹€.

Hard delete

  • 쿼리λ₯Ό 날릴 λ•Œ 이전에 'Delete' μ²˜λ¦¬ν•œ λ ˆμ½”λ“œλ₯Ό μ‹ κ²½μ“Έ ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.
  • λ°μ΄ν„°λ² μ΄μŠ€ μš©λŸ‰μ΄ μƒλŒ€μ μœΌλ‘œ μ ˆμ•½λ©λ‹ˆλ‹€.
  • ν•œλ²ˆ μ‚­μ œν•˜λ©΄ 데이터λ₯Ό λ³΅κ΅¬ν•˜κΈ° νž˜λ“­λ‹ˆλ‹€.

Soft delete

  • 쿼리λ₯Ό 날릴 λ•Œ 이전에 'Delete' μ²˜λ¦¬ν•œ λ ˆμ½”λ“œλ„ μ‹ κ²½μ¨μ€˜μ•Ό ν•©λ‹ˆλ‹€.
  • κ°œμΈμ •λ³΄μ™€ κ΄€λ ¨λœ λ ˆμ½”λ“œλ₯Ό soft delete μ²˜λ¦¬ν•œλ‹€λ©΄ κ°œμΈμ •λ³΄ λ³΄ν˜Έλ²•μ„ μ€€μˆ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • 데이터λ₯Ό λ³΅κ΅¬ν•˜κ±°λ‚˜ λ‹€λ₯Έ μš©λ„λ‘œ ν™œμš©ν•  λ•Œ κ°„νŽΈν•©λ‹ˆλ‹€.

Soft deleteλ₯Ό κ΅¬ν˜„ν•  λ•Œ μ–΄λ–€ μ‹μœΌλ‘œ κ΅¬ν˜„ν• μ§€ κ³ λ―Όλ˜μ—ˆλŠ”λ°μš”, 제 경우 μ‚­μ œλ˜μ—ˆλŠ”μ§€ μ—¬λΆ€λ₯Ό boolean으둜 μ €μž₯ν•˜λŠ” column을 μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€. μ°Ύμ•„λ³΄λ‹ˆ 넀이밍은 보톡 active/inactive, removed, is_deleted 정도가 κ³ λ €λ˜λŠ” κ²ƒμœΌλ‘œ λ³΄μ΄λŠ”λ°, is_deletedκ°€ κ°€μž₯ μ·¨ν–₯에 λ§žμ•˜μŠ΅λ‹ˆλ‹€. booleanκ°’ λŒ€μ‹  μ‚­μ œ μΌμ‹œλ₯Ό datetime으둜 μ €μž₯ν•΄μ„œ, ν•΄λ‹Ή 컬럼이 null인지 μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” λ°©μ‹μœΌλ‘œ κ΄€λ¦¬ν•˜λŠ” μŠ€νƒ€μΌλ„ μžˆμŠ΅λ‹ˆλ‹€.

ν•˜λ‹¨μ€ soft deleteμ‹œ 컬럼 생성에 λŒ€ν•œ λ©˜ν† λ‹˜μ˜ μ˜κ²¬μž…λ‹ˆλ‹€.

image

μ•„ 그리고 이 λ•Œ 살짝 μ°œμ°œν•  μˆ˜λ„ μžˆλŠ” 뢀뢄이 μžˆμŠ΅λ‹ˆλ‹€. Soft deleteλ₯Ό ν•  경우 μ‹€μ œ λ™μž‘μ€ μžμ›μ„ μ‚­μ œν•˜λŠ” 것이 μ•„λ‹ˆλΌ, 컬럼 정보λ₯Ό 일뢀뢄 μ—…λ°μ΄νŠΈν•˜λŠ” μ‹μœΌλ‘œ μž‘λ™ν•˜λ‹ˆκΉŒ PATCHλ‚˜ PUT λ©”μ„œλ“œ, ν˜Ήμ€ POST λ©”μ„œλ“œλ₯Ό ν™œμš©ν•΄μ•Όν• κΉŒμš”??

ν™•μΈν•΄λ³΄λ‹ˆ 이 뢀뢄은 이견이 κ°ˆλ¦¬λŠ” κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€. μ €λŠ” 개인적으둜 DELETE λ©”μ„œλ“œλ₯Ό ν™œμš©ν•˜λŠ” 것이 λ°”λžŒμ§ν•˜λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. μš”μ²­ λ©”μ„œλ“œμ—λŠ” ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­ μ˜λ„κ°€ λ“œλŸ¬λ‚˜λ©΄ μΆ©λΆ„ν•˜λ©°, λ‚΄λΆ€ λ™μž‘μ€ 감좰져 μžˆλŠ” κ²½μš°κ°€ 보톡이기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

πŸ”™ 응닡

A successful response of DELETE requests SHOULD be HTTP response code 200 (OK) if the response includes an entity describing the status, 202 (Accepted) if the action has been queued, or 204 (No Content) if the action has been performed but the response does not include an entity. - RFC 7231

이제 DELETE λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•œ 결과에 따라 μ μ ˆν•œ μƒνƒœ μ½”λ“œλ₯Ό 응닡해주면 λ©λ‹ˆλ‹€.

  • 202(Accepted) : DELETE에 ν•΄λ‹Ήν•˜λŠ” μš”μ²­μ΄ 잘 μ ‘μˆ˜λ˜μ—ˆκ³ , μž‘μ—…μ΄ 싀행될 μ˜ˆμ •μΌ λ•Œ.
  • 204(No Content) : μž‘μ—…μ΄ μˆ˜ν–‰λ˜μ—ˆμœΌλ©° λ³„λ„λ‘œ λ‚΄μš©μ„ λ°˜ν™˜ν• κ²Œ 없을 λ•Œ.
  • 200(OK) : μž‘μ—…μ΄ 잘 μˆ˜ν–‰λ˜μ—ˆκ³ , μž‘μ—…μ— λŒ€ν•œ λ‚΄μš©μ„ λ°˜ν™˜ν•  λ•Œ.
    ex) 제 경우 ν”„λ‘ νŠΈμ—”λ“œλ₯Ό 맑은 λ™λ£Œμ˜ μš”μ²­μ— 따라 μ •μƒμ μœΌλ‘œ μˆ˜ν–‰λ˜μ—ˆμ„ 경우 200 μƒνƒœμ½”λ“œλ₯Ό μ‘λ‹΅ν•˜λ©° μ‚­μ œλœ 데이터에 κ΄€ν•œ 정보λ₯Ό Body에 λ„£μ–΄μ„œ μ‘λ‹΅ν–ˆμŠ΅λ‹ˆλ‹€.

πŸ‘¨πŸ»‍πŸ’» 마치며

API 섀계와 κ΅¬ν˜„μ€ λ”± 베슀트 ν”Œλ ‰ν‹°μŠ€κ°€ μžˆλŠ” 것이 μ•„λ‹ˆλΌ 개발 νŒ€μ˜ 정책에 따라 μ„ νƒν•˜λŠ”κ²Œ λ§žλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. κ·Έλž˜λ„ 각 λ°©μ‹μ˜ μž₯단점을 κ³ λ €ν•΄μ„œ 상황에 맞게 선택할 수 μžˆλ„λ‘ κ³ λ―Όν•  κΈ°νšŒκ°€ μžˆμ„ λ•Œ 미리 κ³ λ―Όν•΄λ‘λŠ” 것이 쒋은 것 κ°™λ„€μš” :)

μœ„μ—μ„œ μ†Œκ°œλ“œλ¦° DELETE λ©”μ„œλ“œ λ‹€λ£¨λŠ” 방식 외에 더 λ‚˜μ€ 방법이 μžˆλ‹€λ©΄ λŒ“κΈ€λ‘œ μ•Œλ €μ£Όμ‹œλ©΄ κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€, μ„±μ‹€νžˆ λ°˜μ˜ν•˜κ² μŠ΅λ‹ˆλ‹€!

πŸ“• μ°Έκ³