๐Ÿ“‹
โ† ๊ฐ€์ด๋“œ ๋ชฉ๋ก์œผ๋กœ

REST API์—์„œ JSON ์‚ฌ์šฉ: ๋ชจ๋ฒ” ์‚ฌ๋ก€

ยท ํƒœ๊ทธ: json, rest-api, api-design, json-best-practices, pagination, web-development

REST API์—์„œ์˜ JSON

JSON๊ณผ REST API๋Š” ์ฒœ์ƒ์—ฐ๋ถ„์ž…๋‹ˆ๋‹ค. JSON์˜ ๊ฐ€๋ฒผ์šด ๊ตฌ๋ฌธ, ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐฐ์—ด ์ง€์› ๋ฐ ๋ณดํŽธ์ ์ธ ์–ธ์–ด ์ง€์›์€ JSON์„ ํ˜„๋Œ€ ์›น API์˜ ๊ธฐ๋ณธ ํ˜•์‹์œผ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ API์—์„œ ๋‹จ์ˆœํžˆ JSON์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค -- ํ™•๋ฆฝ๋œ ๊ทœ์น™๊ณผ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅด๋ฉด API๊ฐ€ ์ผ๊ด€๋˜๊ณ  ์ง๊ด€์ ์ด๋ฉฐ ํ†ตํ•ฉํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

์š”์ฒญ ๋ฐ ์‘๋‹ต ํ˜•์‹

์ผ๊ด€๋œ ์—”๋ฒจ๋กœํ”„ ๊ตฌ์กฐ

๋ชจ๋“  API ์‘๋‹ต์— ์ผ๊ด€๋œ JSON ์—”๋ฒจ๋กœํ”„๋ฅผ ์ฑ„ํƒํ•˜์„ธ์š”. ์ด๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ์ฒ˜๋ฆฌ๋ฅผ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ๋‹จ์ˆœํ™”ํ•ฉ๋‹ˆ๋‹ค.

{
  "status": "success",
  "data": {
    "user": {
      "id": 123,
      "name": "Alice",
      "email": "alice@example.com"
    }
  },
  "meta": {
    "requestId": "req-a1b2c3d4",
    "timestamp": "2026-07-19T10:30:00Z"
  }
}

์Šค๋„ค์ดํฌ ์ผ€์ด์Šค vs ์นด๋ฉœ ์ผ€์ด์Šค

ํ•˜๋‚˜์˜ ๋„ค์ด๋ฐ ๊ทœ์น™์„ ์„ ํƒํ•˜๊ณ  ์ „์ฒด API์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”:

  • ์นด๋ฉœ ์ผ€์ด์Šค (createdAt, firstName): JavaScript/TypeScript ์ƒํƒœ๊ณ„์—์„œ ์ผ๋ฐ˜์ 
  • ์Šค๋„ค์ดํฌ ์ผ€์ด์Šค (created_at, first_name): Python, Ruby, PHP ์ƒํƒœ๊ณ„์—์„œ ์ผ๋ฐ˜์ 

์–ด๋А ๊ฒƒ์„ ์„ ํƒํ•˜๋“  ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฌธ์„œํ™”ํ•˜๊ณ , ๋ฐฑ์—”๋“œ ์–ธ์–ด๊ฐ€ ๋‹ค๋ฅธ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋ณ€ํ™˜ ๊ณ„์ธต์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

JSON๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” HTTP ์ƒํƒœ ์ฝ”๋“œ

์ ์ ˆํ•œ HTTP ์ƒํƒœ ์ฝ”๋“œ๋Š” JSON ์‘๋‹ต์„ ๋ณด์™„ํ•ฉ๋‹ˆ๋‹ค. ์ผ๊ด€๋˜๊ฒŒ ์‚ฌ์šฉํ•˜์„ธ์š”:

| ์ƒํƒœ ์ฝ”๋“œ | ์˜๋ฏธ | ์‚ฌ์šฉ ์‹œ๊ธฐ | |-------------|---------|-------------| | 200 OK | ์„ฑ๊ณต | GET, PUT, PATCH ์„ฑ๊ณต | | 201 Created | ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ๋จ | POST ์„ฑ๊ณต | | 204 No Content | ์‚ญ์ œ ์„ฑ๊ณต | DELETE ์„ฑ๊ณต (JSON ๋ณธ๋ฌธ ์—†์Œ) | | 400 Bad Request | ์ž˜๋ชป๋œ JSON ๊ตฌ๋ฌธ | ์ž˜๋ชป๋œ ํ˜•์‹์˜ ์š”์ฒญ ๋ณธ๋ฌธ | | 401 Unauthorized | ์ธ์ฆ ํ•„์š” | ํ† ํฐ ๋ˆ„๋ฝ ๋˜๋Š” ์œ ํšจํ•˜์ง€ ์•Š์Œ | | 403 Forbidden | ๊ถŒํ•œ ๋ถ€์กฑ | ์œ ํšจํ•œ ์ธ์ฆ์ด์ง€๋งŒ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Œ | | 404 Not Found | ๋ฆฌ์†Œ์Šค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Œ | ์œ ํšจํ•˜์ง€ ์•Š์€ ID ๋˜๋Š” ๊ฒฝ๋กœ | | 422 Unprocessable Entity | ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ | ์œ ํšจํ•œ JSON์˜ ์˜๋ฏธ์  ์˜ค๋ฅ˜ | | 429 Too Many Requests | ์†๋„ ์ œํ•œ ์ดˆ๊ณผ | ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ œํ•œ ์ดˆ๊ณผ | | 500 Internal Server Error | ์„œ๋ฒ„ ์ธก ์‹คํŒจ | ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ค๋ฅ˜ |

ํ‘œ์ค€ ์˜ค๋ฅ˜ ์‘๋‹ต ํ˜•์‹

{
  "status": "error",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "์š”์ฒญ ๋ณธ๋ฌธ์— ์œ ํšจํ•˜์ง€ ์•Š์€ ํ•„๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค",
    "details": [
      {
        "field": "email",
        "message": "์œ ํšจํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค",
        "code": "INVALID_FORMAT"
      },
      {
        "field": "age",
        "message": "์–‘์˜ ์ •์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค",
        "code": "OUT_OF_RANGE"
      }
    ]
  }
}

์ค‘์ฒฉ ๋ฆฌ์†Œ์Šค

๊ด€๊ณ„ ํ‘œํ˜„ํ•˜๊ธฐ

REST API๋Š” ์ข…์ข… ๊ด€๋ จ ๋ฆฌ์†Œ์Šค๋ฅผ ํ‘œํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค:

์ž„๋ฒ ๋””๋“œ (์ฆ‰์‹œ ๋กœ๋”ฉ):

{
  "order": {
    "id": 5001,
    "total": 29.99,
    "customer": {
      "id": 123,
      "name": "Alice",
      "email": "alice@example.com"
    },
    "items": [
      {
        "productId": 42,
        "name": "Widget",
        "quantity": 2,
        "price": 14.99
      }
    ]
  }
}

์ฐธ์กฐ (์ง€์—ฐ ๋กœ๋”ฉ) -- ID๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ณ„๋„์˜ ์—”๋“œํฌ์ธํŠธ ์ œ๊ณต:

{
  "order": {
    "id": 5001,
    "total": 29.99,
    "customerId": 123,
    "itemIds": [101, 102]
  }
}

๊ฒฝํ—˜ ๋ฒ•์น™: ํ•ญ์ƒ ํ•จ๊ป˜ ํ•„์š”ํ•œ ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋Š” ์ž„๋ฒ ๋“œํ•˜์„ธ์š”. ์กฐ๊ฑด๋ถ€๋กœ ๋˜๋Š” ๋‹ค๋ฅธ ์‹œ์ ์— ์กฐํšŒ๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ์ฐธ์กฐํ•˜์„ธ์š”.

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŒจํ„ด

๋ฆฌ์†Œ์Šค ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ผ๊ด€๋œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ํ˜•์‹์„ ์‚ฌ์šฉํ•˜์„ธ์š”:

์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜

{
  "status": "success",
  "data": [
    { "id": 1, "name": "User 1" },
    { "id": 2, "name": "User 2" }
  ],
  "pagination": {
    "page": 1,
    "perPage": 20,
    "totalItems": 156,
    "totalPages": 8,
    "links": {
      "first": "/api/users?page=1&perPage=20",
      "prev": null,
      "next": "/api/users?page=2&perPage=20",
      "last": "/api/users?page=8&perPage=20"
    }
  }
}

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ (๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์…‹์— ๊ถŒ์žฅ)

{
  "status": "success",
  "data": [
    { "id": 100, "name": "User 100" },
    { "id": 101, "name": "User 101" }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6MTAxfQ==",
    "hasMore": true
  }
}

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์ƒˆ ๋ ˆ์ฝ”๋“œ๊ฐ€ ํŽ˜์ด์ง€ ๊ฒฝ๊ณ„๋ฅผ ์ด๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ์— ๋” ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.

API ์š”์ฒญ์—์„œ์˜ JSON

POST / PUT ์š”์ฒญ ๋ณธ๋ฌธ

Content-Type: application/json ํ—ค๋”์™€ ํ•จ๊ป˜ JSON์„ ์ˆ˜๋ฝํ•˜์„ธ์š”:

{
  "title": "์ƒˆ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ",
  "content": "์ด๊ฒƒ์€ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค...",
  "tags": ["json", "rest-api"],
  "published": false
}

PATCH๋ฅผ ์‚ฌ์šฉํ•œ ๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ

๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ์—๋Š” PATCH๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ํ•„๋“œ๋งŒ ์ˆ˜๋ฝํ•˜์„ธ์š”:

// PATCH /api/users/123
{
  "email": "newemail@example.com"
}

ํ•„ํ„ฐ๋ง, ์ •๋ ฌ ๋ฐ ๊ฒ€์ƒ‰

๋ฐ์ดํ„ฐ ์กฐ์ž‘์—๋Š” ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JSON ๋ณธ๋ฌธ์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”:

GET /api/users?filter[role]=admin&sort=-createdAt&search=alice
{
  "status": "success",
  "data": [ /* ํ•„ํ„ฐ๋ง๋˜๊ณ  ์ •๋ ฌ๋œ ๊ฒฐ๊ณผ */ ]
}

์†๋„ ์ œํ•œ

์‘๋‹ต ํ—ค๋”์™€ ์„ ํƒ์ ์œผ๋กœ JSON ๋ณธ๋ฌธ์— ์†๋„ ์ œํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜์„ธ์š”:

{
  "status": "error",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "์š”์ฒญ์ด ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”."
  },
  "meta": {
    "rateLimit": {
      "limit": 100,
      "remaining": 0,
      "resetAt": "2026-07-19T11:00:00Z"
    }
  }
}

JSON ๋ชจ๋ฒ” ์‚ฌ๋ก€ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • [ ] ์ „์ฒด์ ์œผ๋กœ ์ผ๊ด€๋œ ํ‚ค ๋„ค์ด๋ฐ ์‚ฌ์šฉ (camelCase ๋˜๋Š” snake_case)
  • [ ] ๋ชจ๋“  ์‘๋‹ต์— ์ ์ ˆํ•œ HTTP ์ƒํƒœ ์ฝ”๋“œ ๋ฐ˜ํ™˜
  • [ ] ๊ธฐ๊ณ„๊ฐ€ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฅ˜ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์ผ๊ด€๋œ ์˜ค๋ฅ˜ ํ˜•์‹ ํฌํ•จ
  • [ ] ํ‘œ์ค€ํ™”๋œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ฐ์ฒด๋กœ ๋ชฉ๋ก ์—”๋“œํฌ์ธํŠธ ํŽ˜์ด์ง€๋„ค์ด์…˜
  • [ ] JSON Schema๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ/์‘๋‹ต ๊ตฌ์กฐ ๋ฌธ์„œํ™” ๋ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
  • [ ] ๋ชจ๋“  JSON ์—”๋“œํฌ์ธํŠธ์— Content-Type: application/json ์„ค์ •
  • [ ] ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ gzip ๋˜๋Š” brotli๋กœ JSON ์‘๋‹ต ์••์ถ•
  • [ ] ์ตœ๋Œ€ ํŽ˜์ด๋กœ๋“œ ํฌ๊ธฐ ์ œํ•œ ์ ์šฉ (์˜ˆ: ๊ธฐ๋ณธ 1MB)
  • [ ] HTTPS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ „์†ก ์ค‘์ธ JSON ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”
  • [ ] ๋‚ด๋ถ€ ์ •๋ณด๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ํด๋ผ์ด์–ธํŠธ ๋””๋ฒ„๊น…์— ๋„์›€์ด ๋˜๋„๋ก ์˜ค๋ฅ˜ ์„ธ๋ถ€ ์ •๋ณด ๊ตฌ์กฐํ™”

API JSON ์œ ํšจ์„ฑ ๊ฒ€์‚ฌํ•˜๊ธฐ

API ์‘๋‹ต์„ JSON ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ์— ์‹คํ–‰ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ํฌ๋งท ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋‚ด์„ธ์š”. ์ผ๊ด€๋˜๊ณ  ์œ ํšจํ•œ JSON ์‘๋‹ต์€ API๋ฅผ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ์ค‘์— ํŽ˜์ด๋กœ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ์ €ํฌ JSON ํฌ๋งทํ„ฐ & ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

REST API์—์„œ JSON ์‚ฌ์šฉ: ๋ชจ๋ฒ” ์‚ฌ๋ก€ - CoolTool