alltools.one
Development
2024-01-01
12 min
Development Team
json-apirest-apiapi-designweb-developmentbackend

JSON API 최고 관행: RESTful API 설계 완전 가이드

견고한 JSON API를 구축하려면 JSON 형식으로 데이터를 반환하는 것 이상이 필요합니다. 이 종합 가이드는 보안, 성능, 개발자 친화적인 API를 설계, 구현 및 유지보수하기 위한 필수 최고 관행을 다룹니다.

API 우수성: 이러한 최고 관행을 따르면 API 채택률을 300% 향상시키고 통합 시간을 70% 줄일 수 있습니다. 잘 설계된 API는 성공적인 디지털 제품의 기반이 됩니다.

JSON API 최고 관행이 중요한 이유

좋은 API 설계의 영향

잘 설계된 API는 제공합니다:

  • 개발자를 위한 더 빠른 통합
  • 감소된 지원 요청 및 문서화 필요
  • 높은 채택률 및 개발자 만족도
  • 쉬운 유지보수 및 시간 경과에 따른 진화
  • 더 나은 성능 및 확장성

일반적인 API 문제

나쁜 API 설계는 다음으로 이어집니다:

  • 개발자를 혼란스럽게 하는 불일치된 응답
  • 부적절한 인증으로 인한 보안 취약점
  • 비효율적인 데이터 전송으로 인한 성능 문제
  • 불명확한 문서화로 인한 통합 실패
  • 기술 부채로 인한 유지보수 악몽

RESTful API 기초

REST 원칙

Representational State Transfer (REST) 핵심 원칙:

  1. 클라이언트-서버 아키텍처: 명확한 관심사 분리
  2. 상태 비저장: 각 요청은 필요한 모든 정보를 포함
  3. 캐시 가능: 적절할 때 응답을 캐시 가능하게
  4. 통일 인터페이스: 일관된 리소스 식별 및 조작
  5. 계층 시스템: 계층적 레이어로 구성될 수 있는 아키텍처

HTTP 메서드 및 적절한 사용

표준 HTTP 메서드:

GET /api/users          # 모든 사용자 검색
GET /api/users/123      # 특정 사용자 검색
POST /api/users         # 새 사용자 생성
PUT /api/users/123      # 전체 사용자 리소스 업데이트
PATCH /api/users/123    # 사용자 부분 업데이트
DELETE /api/users/123   # 사용자 삭제

메서드 지침:

  • GET: 안전하고 멱등, 부작용 없음
  • POST: 멱등하지 않음, 리소스 생성
  • PUT: 멱등, 전체 리소스 교체
  • PATCH: 반드시 멱등하지 않음, 부분 업데이트
  • DELETE: 멱등, 리소스 제거

URL 구조 및 명명 규칙

리소스 기반 URL

좋은 URL 설계:

✅ GET /api/v1/users
✅ GET /api/v1/users/123
✅ GET /api/v1/users/123/orders
✅ POST /api/v1/orders

이 패턴 피하기:

❌ GET /api/getUsers
❌ POST /api/createUser
❌ GET /api/user_orders?userId=123

명명 규칙

리소스 명명 규칙:

  • 컬렉션에는 복수 명사 사용 (/users, /user 아님)
  • 가독성을 위해 소문자와 하이픈 사용 (/user-profiles)
  • 전체 API에서 일관성 유지
  • 관계를 위해 중첩 리소스 사용 (/users/123/orders)

쿼리 매개변수:

GET /api/users?page=2&limit=50&sort=created_at&order=desc
GET /api/products?category=electronics&min_price=100
GET /api/posts?search=json&tags=api,development

JSON 응답 구조

일관된 응답 형식

표준 성공 응답:

{
  "success": true,
  "data": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com",
    "created_at": "2024-01-01T10:00:00Z"
  },
  "message": "User retrieved successfully"
}

컬렉션 응답:

{
  "success": true,
  "data": [
    {
      "id": 123,
      "name": "John Doe",
      "email": "john@example.com"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 1250,
    "pages": 25,
    "has_next": true,
    "has_prev": false
  },
  "message": "Users retrieved successfully"
}

데이터 형식 표준

날짜 및 시간:

{
  "created_at": "2024-01-01T10:00:00Z",
  "updated_at": "2024-01-01T15:30:00Z"
}

통화 값:

{
  "price": {
    "amount": 1999,
    "currency": "USD",
    "formatted": "$19.99"
  }
}

불리언 값:

{
  "is_active": true,
  "email_verified": false,
  "has_premium": null
}

오류 처리 최고 관행

HTTP 상태 코드

성공 코드:

  • 200 OK: 성공적인 GET, PUT, PATCH
  • 201 Created: 성공적인 POST
  • 204 No Content: 성공적인 DELETE

클라이언트 오류 코드:

  • 400 Bad Request: 잘못된 요청 데이터
  • 401 Unauthorized: 인증 필요
  • 403 Forbidden: 액세스 거부
  • 404 Not Found: 리소스 존재하지 않음
  • 422 Unprocessable Entity: 유효성 검사 오류

서버 오류 코드:

  • 500 Internal Server Error: 일반 서버 오류
  • 502 Bad Gateway: 상위 서버 오류
  • 503 Service Unavailable: 일시적 이용 불가

오류 응답 형식

표준 오류 응답:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request data is invalid",
    "details": [
      {
        "field": "email",
        "message": "Email format is invalid",
        "rejected_value": "invalid-email"
      },
      {
        "field": "age",
        "message": "Age must be between 18 and 120",
        "rejected_value": 15
      }
    ]
  },
  "timestamp": "2024-01-01T10:00:00Z",
  "request_id": "req_123456789"
}

보안 경고: 오류 메시지에 민감한 정보를 노출하지 마세요. 시스템 내부나 사용자 데이터를 드러내지 않고 디버깅을 위한 충분한 세부 정보를 제공하세요.

인증 및 권한 부여

인증 방법

API 키 인증:

GET /api/users
Authorization: Bearer api_key_here

JWT 토큰 인증:

GET /api/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

OAuth 2.0:

GET /api/users
Authorization: Bearer oauth_access_token_here

보안 최고 관행

필수 보안 조치:

  • HTTPS 전용: HTTP를 통해 민감한 데이터 전송 금지
  • 속도 제한: 남용 및 DoS 공격 방지
  • 입력 유효성 검사: 모든 입력을 세정 및 유효성 검사
  • 출력 인코딩: XSS 공격 방지
  • CORS 구성: 교차 출처 요청 적절히 구성

속도 제한 헤더:

HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200

페이지네이션 전략

오프셋 기반 페이지네이션

요청:

GET /api/users?page=2&limit=50

응답:

{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 50,
    "total": 1250,
    "pages": 25,
    "offset": 50
  }
}

커서 기반 페이지네이션

요청:

GET /api/users?cursor=eyJpZCI6MTIzfQ&limit=50

응답:

{
  "data": [...],
  "pagination": {
    "limit": 50,
    "has_next": true,
    "next_cursor": "eyJpZCI6MTczfQ",
    "prev_cursor": "eyJpZCI6NzN9"
  }
}

링크 헤더 페이지네이션

응답 헤더:

Link: <https://api.example.com/users?page=1>; rel="first",
      <https://api.example.com/users?page=2>; rel="prev",
      <https://api.example.com/users?page=4>; rel="next",
      <https://api.example.com/users?page=25>; rel="last"

필터링, 정렬 및 검색

쿼리 매개변수 규칙

필터링:

GET /api/products?category=electronics&status=active&min_price=100
GET /api/users?role=admin&created_after=2024-01-01

정렬:

GET /api/users?sort=created_at&order=desc
GET /api/products?sort=price,name&order=asc,desc

검색:

GET /api/users?search=john&fields=name,email
GET /api/posts?q=json%20api&in=title,content

고급 필터링

연산자:

GET /api/products?price[gte]=100&price[lte]=500
GET /api/users?created_at[between]=2024-01-01,2024-12-31
GET /api/posts?tags[in]=api,json,rest

버전 관리 전략

URL 경로 버전 관리

GET /api/v1/users
GET /api/v2/users

헤더 버전 관리

GET /api/users
Accept: application/vnd.api+json;version=1
API-Version: 2

쿼리 매개변수 버전 관리

GET /api/users?version=1

버전 관리 최고 관행:

  • 시맨틱 버전 관리: major.minor.patch 형식 사용
  • 후방 호환성: 합리적인 기간 동안 이전 버전 유지
  • 사용 중단 통지: 명확한 마이그레이션 경로 제공
  • 문서화: 버전별 문서 유지

성능 최적화

응답 최적화

필드 선택:

GET /api/users?fields=id,name,email
GET /api/posts?include=author,comments&fields[posts]=title,body&fields[author]=name

압축:

Accept-Encoding: gzip, deflate
Content-Encoding: gzip

캐싱 전략

HTTP 캐싱 헤더:

Cache-Control: public, max-age=3600
ETag: "abc123def456"
Last-Modified: Wed, 01 Jan 2024 10:00:00 GMT

조건부 요청:

GET /api/users/123
If-None-Match: "abc123def456"
If-Modified-Since: Wed, 01 Jan 2024 10:00:00 GMT

데이터베이스 최적화

N+1 쿼리 방지:

{
  "data": [
    {
      "id": 1,
      "title": "Post Title",
      "author": {
        "id": 123,
        "name": "John Doe"
      },
      "comments": [
        {
          "id": 456,
          "content": "Great post!",
          "author": {
            "id": 789,
            "name": "Jane Smith"
          }
        }
      ]
    }
  ]
}

콘텐츠 협상

Accept 헤더

JSON 응답:

Accept: application/json
Content-Type: application/json

XML 응답:

Accept: application/xml
Content-Type: application/xml

다중 형식 지원

API 응답:

GET /api/users/123
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "John Doe"
}

문서화 최고 관행

OpenAPI/Swagger 사양

기본 API 정의:

openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
  description: A simple user management API

paths:
  /users:
    get:
      summary: Get all users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'

상호작용 문서화

필수 문서화 요소:

  • 모든 엔드포인트에 대한 명확한 설명
  • 모든 작업에 대한 요청/응답 예시
  • 오류 시나리오 및 응답
  • 인증 요구사항 및 예시
  • 속도 제한 정보
  • 여러 언어의 SDK 및 코드 샘플

테스트 전략

API 테스트 피라미드

단위 테스트:

describe('User API', () => {
  test('should create user with valid data', async () => {
    const userData = {
      name: 'John Doe',
      email: 'john@example.com'
    };
    
    const response = await request(app)
      .post('/api/users')
      .send(userData)
      .expect(201);
      
    expect(response.body.data.name).toBe('John Doe');
  });
});

통합 테스트:

describe('User Integration Tests', () => {
  test('should handle user creation workflow', async () => {
    // Create user
    const createResponse = await createUser(userData);
    expect(createResponse.status).toBe(201);
    
    // Verify user exists
    const getResponse = await getUser(createResponse.body.data.id);
    expect(getResponse.status).toBe(200);
    
    // Update user
    const updateResponse = await updateUser(user.id, updatedData);
    expect(updateResponse.status).toBe(200);
  });
});

계약 테스트

API 계약 예시:

{
  "consumer": "Frontend App",
  "provider": "User API",
  "interactions": [
    {
      "description": "Get user by ID",
      "request": {
        "method": "GET",
        "path": "/api/users/123"
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json"
        },
        "body": {
          "id": 123,
          "name": "John Doe",
          "email": "john@example.com"
        }
      }
    }
  ]
}

모니터링 및 분석

필수 지표

성능 지표:

  • 응답 시간 백분위수 (p50, p95, p99)
  • 요청 속도 및 처리량
  • 엔드포인트 및 상태 코드별 오류 비율
  • 캐시 적중/실패 비율

비즈니스 지표:

  • API 채택 및 사용 패턴
  • 가장 인기 있는 엔드포인트
  • 개발자 온보딩 성공률
  • 지원 티켓 카테고리

로깅 최고 관행

구조화된 로깅:

{
  "timestamp": "2024-01-01T10:00:00Z",
  "level": "INFO",
  "method": "GET",
  "path": "/api/users/123",
  "status_code": 200,
  "response_time": 150,
  "user_id": "user_456",
  "request_id": "req_789",
  "ip_address": "192.168.1.1"
}

고급 주제

웹훅 구현

웹훅 페이로드:

{
  "event": "user.created",
  "timestamp": "2024-01-01T10:00:00Z",
  "data": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com"
  },
  "webhook_id": "wh_abc123"
}

GraphQL vs REST

GraphQL 선택 시:

  • 복잡한 데이터 관계
  • 다양한 요구사항의 여러 클라이언트 유형
  • 실시간 구독 필요
  • 강한 타이핑 요구사항

REST 유지 시:

  • 간단한 CRUD 작업
  • 캐싱이 중요
  • 팀의 REST 친숙도
  • 파일 업로드/다운로드 중심

API 진화 및 유지보수

사용 중단 전략

사용 중단 프로세스:

  1. 사용 중단 발표 명확한 타임라인과 함께
  2. 마이그레이션 가이드 및 예시 제공
  3. 사용 중단 엔드포인트 사용 모니터링
  4. 전환 기간 동안 지원 제공
  5. 유예 기간 후 사용 중단 기능 제거

파괴적 vs 비파괴적 변경

비파괴적 변경:

  • 새 선택적 필드 추가
  • 새 엔드포인트 추가
  • 새 선택적 쿼리 매개변수 추가
  • 필수 필드를 선택적으로 변경

파괴적 변경:

  • 필드 또는 엔드포인트 제거
  • 필드 유형 또는 형식 변경
  • 선택적 필드를 필수로 변경
  • 인증 요구사항 변경

결론

우수한 JSON API를 구축하려면 세부 사항에 대한 주의, 일관성, 기술적 및 사용자 경험 고려사항에 대한 깊은 이해가 필요합니다. 최고의 API는 개발자에게 직관적이며, 빠른 통합 및 개발을 가능하게 하는 명확하고 예측 가능한 인터페이스를 제공합니다.

API 설계는 서비스와 소비자 간의 계약을 만드는 것입니다. 그 계약을 최대한 명확하고 안정적이며 개발자 친화적으로 만드세요. 그러면 API는 채택과 비즈니스 성공을 촉진하는 귀중한 자산이 됩니다.

API 성공의 핵심은 API를 제품으로 취급하는 것입니다, 실제 요구사항이 있는 실제 사용자와 함께. 공감으로 설계하고, 철저히 문서화하며, 피드백에 기반해 반복하세요.

더 나은 API를 구축할 준비가 되셨나요? API 응답이 적절히 형식화되고 유효성 검사되었는지 확인하기 위해 JSON Formatter를 사용하세요.

Published on 2024-01-01 by Development Team