Skip to content

Latest commit

ย 

History

History
132 lines (105 loc) ยท 5.37 KB

api-response.md

File metadata and controls

132 lines (105 loc) ยท 5.37 KB

๊ณตํ†ต API ์‘๋‹ต๊ณผ ์ „์—ญ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ณ„์•ฝ

์ƒํƒœ: ๊ตฌํ˜„ ์™„๋ฃŒ

์ด ๋ฌธ์„œ๋Š” ๊ณŒ๋ฆฐ๋” API์˜ JSON ์„ฑ๊ณตยท์˜ค๋ฅ˜ ์‘๋‹ต ํ˜•์‹๊ณผ ์ „์—ญ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ทœ์น™์„ ์ •์˜ํ•œ๋‹ค. /docs, /openapi.json๊ณผ body๊ฐ€ ์—†๋Š” 204 No Content ์‘๋‹ต์€ envelope ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค.

์„ฑ๊ณต ์‘๋‹ต

JSON body๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ์ •์ƒ ์‘๋‹ต์€ ๋‹ค์Œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

{
  "success": true,
  "data": {
    "id": "6b6e46da-65db-4b06-acbc-ecf4283fb03d"
  },
  "error": null
}
  • success๋Š” ํ•ญ์ƒ true๋‹ค.
  • data์—๋Š” ๊ธฐ์กด endpoint์˜ ์‹ค์ œ ์‘๋‹ต ๊ฐ์ฒด, ๋ฐฐ์—ด ๋˜๋Š” ์ƒํƒœ๊ฐ’์ด ๋“ค์–ด๊ฐ„๋‹ค.
  • error๋Š” ํ•ญ์ƒ null์ด๋‹ค.
  • ๋ชฉ๋ก์ด ๋น„์–ด ์žˆ์œผ๋ฉด data๋Š” []๋‹ค. ์„ฑ๊ณต ์‘๋‹ต์˜ data๋ฅผ null๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๊ณผ์ œ ์‚ญ์ œ ์„ฑ๊ณต์€ 204 No Content์™€ ๋นˆ body๋ฅผ ์œ ์ง€ํ•œ๋‹ค.

์˜ค๋ฅ˜ ์‘๋‹ต

์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  API ์˜ค๋ฅ˜๋Š” ๋‹ค์Œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

{
  "success": false,
  "data": null,
  "error": {
    "code": "ASSIGNMENT_NOT_FOUND",
    "message": "๊ณผ์ œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
    "details": null
  }
}
  • success๋Š” ํ•ญ์ƒ false๋‹ค.
  • data๋Š” ํ•ญ์ƒ null์ด๋‹ค.
  • error.code๋Š” ํด๋ผ์ด์–ธํŠธ ๋ถ„๊ธฐ์šฉ ์•ˆ์ •์ ์ธ ์˜๋ฌธ ๋Œ€๋ฌธ์ž code๋‹ค.
  • error.message๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ ๊ฐ€๋Šฅํ•œ ํ•œ๊ตญ์–ด ์„ค๋ช…์ด๋‹ค.
  • error.details๋Š” ์ž…๋ ฅ ๊ฒ€์ฆ ์˜ค๋ฅ˜์—๋งŒ ๋ฐฐ์—ด์ด๋ฉฐ ๊ทธ ์™ธ์—๋Š” null์ด๋‹ค.
  • stack trace, SQL, ๋น„๋ฐ€๋ฒˆํ˜ธ, JWT, ์š”์ฒญ body๋Š” ์‘๋‹ต๊ณผ ๋กœ๊ทธ์— ํฌํ•จํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ž…๋ ฅ ๊ฒ€์ฆ ์˜ค๋ฅ˜

FastAPI/Pydantic ๊ฒ€์ฆ ์‹คํŒจ๋Š” 422 VALIDATION_ERROR๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

{
  "success": false,
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "์š”์ฒญ ๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.",
    "details": [
      {
        "field": "body.studentNumber",
        "message": "String should match pattern '^[0-9]{5}$'",
        "type": "string_pattern_mismatch"
      }
    ]
  }
}

๊ฒ€์ฆ detail์€ field, message, type๋งŒ ์ œ๊ณตํ•œ๋‹ค. Pydantic์˜ ์ž…๋ ฅ ์›๋ฌธ๊ณผ ๋‚ด๋ถ€ context๋Š” ๋…ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ „์—ญ ์˜ˆ์™ธ ๋ณ€ํ™˜

๋ฐœ์ƒ ์˜ˆ์™ธ HTTP ์ƒํƒœ ๊ธฐ๋ณธ code ์ฒ˜๋ฆฌ ๊ทœ์น™
๋ช…์‹œ์  HTTPException ์›๋ž˜ ์ƒํƒœ ์œ ์ง€ ์˜ˆ์™ธ์— ์ง€์ •๋œ code ๊ธฐ์กด codeยทmessage์™€ header ๋ณด์กด
๋ผ์šฐํŒ… 404 404 NOT_FOUND ์กด์žฌํ•˜์ง€ ์•Š๋Š” API ๊ฒฝ๋กœ
ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ method 405 METHOD_NOT_ALLOWED framework ์˜ค๋ฅ˜๋ฅผ ๊ณตํ†ต ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
RequestValidationError 422 VALIDATION_ERROR ์•ˆ์ „ํ•œ field detail๋งŒ ๋ฐ˜ํ™˜
SQLAlchemyError 503 DATABASE_UNAVAILABLE ๋‚ด๋ถ€ ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•˜๊ณ  DB ์ •๋ณด๋Š” ์ˆจ๊น€
๊ทธ ์™ธ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ 500 INTERNAL_SERVER_ERROR ๋‚ด๋ถ€ ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ๊ณ ์ • ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜

์ธ์ฆ ์˜ค๋ฅ˜์˜ WWW-Authenticate: Bearer์ฒ˜๋Ÿผ ๊ธฐ์กด HTTP header๊ฐ€ ์žˆ์œผ๋ฉด ์ „์—ญ handler๊ฐ€ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•œ๋‹ค.

๊ธฐ์กด ์—…๋ฌด ์˜ค๋ฅ˜ code

Code ์ƒํƒœ ์˜๋ฏธ
EMAIL_ALREADY_EXISTS 409 ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ธ ์ด๋ฉ”์ผ
INVALID_CREDENTIALS 401 ๋กœ๊ทธ์ธ ์ •๋ณด ๋ถˆ์ผ์น˜
INVALID_TOKEN 401 token ์—†์Œ, ์œ„์กฐ, ๋งŒ๋ฃŒ ๋˜๋Š” ์‚ฌ์šฉ์ž ์—†์Œ
ASSIGNMENT_NOT_FOUND 404 ๊ณผ์ œ๊ฐ€ ์—†๊ฑฐ๋‚˜ ํ˜„์žฌ ์‚ฌ์šฉ์ž ์†Œ์œ ๊ฐ€ ์•„๋‹˜
INVALID_IMAGE 400 ์ง€์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ œํ•œ์„ ์ดˆ๊ณผํ•œ ์ด๋ฏธ์ง€
AI_RATE_LIMITED 429 ์‚ฌ์ง„ ๋ถ„์„ ํ˜ธ์ถœ ๋˜๋Š” ์™ธ๋ถ€ ์‚ฌ์šฉ๋Ÿ‰ ์ œํ•œ ๋„๋‹ฌ
AI_EXTRACTION_FAILED 502 ์™ธ๋ถ€ ์‚ฌ์ง„ ๋ถ„์„ ์‹คํŒจ ๋˜๋Š” ์œ ํšจํ•œ ๊ตฌ์กฐํ™” ๊ฒฐ๊ณผ ์—†์Œ
AI_EXTRACTION_DISABLED 503 ์‚ฌ์ง„ ๋ถ„์„ ๊ธฐ๋Šฅ ๋น„ํ™œ์„ฑํ™” ๋˜๋Š” API key ๋ฏธ์„ค์ •

์—…๋ฌด ์˜ค๋ฅ˜๋ฅผ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  ๋•Œ endpoint์—์„œ๋Š” HTTPException์— code์™€ message๋งŒ ์ง€์ •ํ•˜๊ณ , JSON envelope ์ƒ์„ฑ์€ ์ „์—ญ handler์— ๋งก๊ธด๋‹ค.

๊ตฌํ˜„ ๊ฒฝ๊ณ„

  • app/responses.py: ์„ฑ๊ณตยท์˜ค๋ฅ˜ Pydantic model๊ณผ ์„ฑ๊ณต helper
  • app/exceptions.py: HTTP, ๊ฒ€์ฆ, DB, ๋ฏธ์ฒ˜๋ฆฌ ์˜ˆ์™ธ handler์™€ ๋“ฑ๋ก ํ•จ์ˆ˜
  • app/main.py: handler๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•œ ๋ฒˆ ๋“ฑ๋ก
  • ๊ธฐ์กด router: ์„ฑ๊ณต response model์„ ๊ณตํ†ต generic envelope๋กœ ๋ณ€๊ฒฝ

middleware๋กœ ์‘๋‹ต body๋ฅผ ์‚ฌํ›„ ๋ณ€ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. endpoint์˜ response_model ์ž์ฒด๊ฐ€ ์‹ค์ œ envelope๋ฅผ ํ‘œํ˜„ํ•ด์•ผ OpenAPI์™€ ๋Ÿฐํƒ€์ž„ ์‘๋‹ต์ด ์ผ์น˜ํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค

์‹œ๋‚˜๋ฆฌ์˜ค ๊ธฐ๋Œ€ ๊ฒฐ๊ณผ
๊ฐ€์ž…ยท๋กœ๊ทธ์ธยท๊ณผ์ œยท๋Œ€์‹œ๋ณด๋“œ ์„ฑ๊ณต success=true, ์‹ค์ œ ๊ฐ’์€ data, error=null
๋นˆ ๊ณผ์ œ ๋ชฉ๋ก data=[]
๊ณผ์ œ ์‚ญ์ œ 204, ๋นˆ body
์ž˜๋ชป๋œ ์ž…๋ ฅ 422 VALIDATION_ERROR, ์•ˆ์ „ํ•œ details
๊ธฐ์กด ์ธ์ฆยท์—…๋ฌด ์˜ค๋ฅ˜ ๊ธฐ์กด HTTP ์ƒํƒœ์™€ code ์œ ์ง€
์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ๋กœ 404 NOT_FOUND ๊ณตํ†ต ์˜ค๋ฅ˜ ์‘๋‹ต
DB ์˜ˆ์™ธ 503 DATABASE_UNAVAILABLE, SQL ๋ฏธ๋…ธ์ถœ
์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ ์˜ˆ์™ธ 500 INTERNAL_SERVER_ERROR, ๋‚ด๋ถ€ ๋ฉ”์‹œ์ง€ ๋ฏธ๋…ธ์ถœ
OpenAPI ์„ฑ๊ณต endpoint๊ฐ€ ApiResponse[...] schema๋ฅผ ํ‘œ์‹œ

์™„๋ฃŒ ์กฐ๊ฑด

  • JSON body๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ํ˜„์žฌ endpoint๊ฐ€ ์„ฑ๊ณต envelope๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • framework์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜ค๋ฅ˜๊ฐ€ ๊ณตํ†ต ์˜ค๋ฅ˜ envelope๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ธ์ฆ header์™€ ์—…๋ฌด ์˜ค๋ฅ˜ code๊ฐ€ ๋ณด์กด๋œ๋‹ค.
  • validation ์‘๋‹ต์— ์š”์ฒญ ์ž…๋ ฅ ์›๋ฌธ์ด ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • 204์™€ OpenAPI ๋ฌธ์„œ endpoint๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ฐ์‹ธ์ง€์ง€ ์•Š๋Š”๋‹ค.
  • make check์™€ git diff --check๊ฐ€ ์„ฑ๊ณตํ•œ๋‹ค.