REST API์์ JSON ์ฌ์ฉ: ๋ชจ๋ฒ ์ฌ๋ก
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 ํฌ๋งทํฐ & ์ ํจ์ฑ ๊ฒ์ฌ๊ธฐ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ธ์.