WIA-LEG-009 · Phase 2 · API 인터페이스

제5장: 2단계 API 인터페이스

REST 엔드포인트, GraphQL, 그리고 삭제 워크플로우

5.1 Phase 2 개요

Phase 2는 표준화된 데이터 형식(Phase 1)을 프로그래밍 방식으로 처리할 수 있는 API 인터페이스를 제공합니다. REST 및 GraphQL 엔드포인트를 통해 삭제 요청의 제출, 추적, 관리를 자동화합니다.

Phase 2의 이점

  • 자동화: 수동 프로세스 제거, 대량 요청 처리
  • 실시간 추적: 요청 상태를 실시간으로 확인
  • 통합 용이성: 기존 시스템과 쉽게 통합
  • 확장성: 수천 개의 요청도 효율적으로 처리
  • 콜백 지원: 완료 시 자동 알림

API 아키텍처

WIA-LEG-009 API는 RESTful 원칙을 따르며, 선택적으로 GraphQL도 지원합니다:

  • Base URL: https://api.example.com/wia/rtbf/v1
  • 인증: OAuth 2.0, API Key, JWT
  • 형식: JSON (Content-Type: application/json)
  • 버전 관리: URL 경로에 버전 포함 (/v1, /v2 등)

5.2 인증 및 권한

API Key 인증

가장 간단한 인증 방식. 요청 헤더에 API 키를 포함:

GET /wia/rtbf/v1/requests
Authorization: Bearer wia_api_key_abc123def456
Content-Type: application/json

OAuth 2.0 인증

더 안전한 인증 방식. Client Credentials Flow 권장:

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=your_client_id
&client_secret=your_client_secret
&scope=rtbf:read rtbf:write

Response:
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "rtbf:read rtbf:write"
}

권한 스코프

스코프 권한
rtbf:read 요청 조회 및 상태 확인
rtbf:write 요청 생성 및 수정
rtbf:delete 요청 취소 및 삭제
rtbf:admin 모든 작업 (관리자)

5.3 핵심 REST 엔드포인트

POST /wia/rtbf/v1/requests

목적: 새로운 삭제 요청 생성

인증: 필수 (OAuth 2.0 또는 API Key)

요청 본문:

{
  "wia_standard": "WIA-LEG-009",
  "version": "1.0",
  "request_type": "deletion",
  "data_subject": {
    "email": "user@example.com",
    "identifiers": [
      {"type": "user_id", "value": "12345"}
    ]
  },
  "legal_basis": "GDPR_Article_17_1a",
  "scope": {
    "data_categories": ["personal_data"],
    "include_backups": true
  },
  "callback_url": "https://your-app.com/rtbf/callback"
}

응답:

202 Accepted

{
  "request_id": "rtbf_20250101_abc123",
  "status": "pending_verification",
  "created_at": "2025-01-01T10:30:00Z",
  "estimated_completion": "2025-01-30T23:59:59Z",
  "verification": {
    "method": "email_otp",
    "expires_at": "2025-01-01T11:00:00Z"
  },
  "links": {
    "self": "/wia/rtbf/v1/requests/rtbf_20250101_abc123",
    "verify": "/wia/rtbf/v1/requests/rtbf_20250101_abc123/verify"
  }
}
GET /wia/rtbf/v1/requests/{request_id}

목적: 특정 요청의 상태 조회

응답:

200 OK

{
  "request_id": "rtbf_20250101_abc123",
  "status": "processing",
  "created_at": "2025-01-01T10:30:00Z",
  "verified_at": "2025-01-01T10:35:00Z",
  "progress": {
    "total_systems": 5,
    "completed_systems": 2,
    "percentage": 40
  },
  "timeline": [
    {
      "event": "request_created",
      "timestamp": "2025-01-01T10:30:00Z"
    },
    {
      "event": "identity_verified",
      "timestamp": "2025-01-01T10:35:00Z"
    },
    {
      "event": "deletion_started",
      "timestamp": "2025-01-01T11:00:00Z",
      "system": "customer_database"
    }
  ]
}
POST /wia/rtbf/v1/requests/{request_id}/verify

목적: 신원 확인 코드 제출

요청 본문:

{
  "verification_code": "123456",
  "method": "email_otp"
}

응답:

200 OK

{
  "verified": true,
  "message": "Identity verified successfully",
  "next_status": "processing"
}
GET /wia/rtbf/v1/requests

목적: 모든 요청 목록 조회 (페이지네이션)

쿼리 파라미터:

  • page: 페이지 번호 (기본값: 1)
  • limit: 페이지당 항목 수 (기본값: 20, 최대: 100)
  • status: 상태 필터 (pending, processing, completed, failed)
  • email: 데이터 주체 이메일 필터
  • from_date: 시작 날짜 (ISO 8601)
  • to_date: 종료 날짜 (ISO 8601)

응답:

200 OK

{
  "requests": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "total_pages": 8
  }
}
DELETE /wia/rtbf/v1/requests/{request_id}

목적: 요청 취소 (처리 전에만 가능)

응답:

200 OK

{
  "message": "Request cancelled successfully",
  "request_id": "rtbf_20250101_abc123",
  "status": "cancelled"
}
GET /wia/rtbf/v1/requests/{request_id}/certificate

목적: 삭제 완료 증명서 다운로드

응답:

200 OK
Content-Type: application/pdf

[PDF 바이너리 데이터]

5.4 요청 상태 머신

요청은 다음 상태를 거쳐 진행됩니다:

┌────────────────┐
│  created       │ ← 요청 생성
└────────┬───────┘
         │
         ▼
┌────────────────┐
│ pending_       │ ← 신원 확인 대기
│ verification   │
└────────┬───────┘
         │
         ▼
┌────────────────┐
│ verified       │ ← 신원 확인 완료
└────────┬───────┘
         │
         ▼
┌────────────────┐
│ legal_review   │ ← 법적 검토 (예외 사항 확인)
└────────┬───────┘
         │
         ├──────────────────┐
         │                  │
         ▼                  ▼
┌────────────────┐   ┌──────────────┐
│ processing     │   │ rejected     │ ← 법적 사유로 거부
└────────┬───────┘   └──────────────┘
         │
         ▼
┌────────────────┐
│ completed      │ ← 삭제 완료
└────────────────┘

         또는

┌────────────────┐
│ failed         │ ← 기술적 오류로 실패
└────────────────┘

         또는

┌────────────────┐
│ cancelled      │ ← 사용자가 취소
└────────────────┘

상태 설명

상태 설명 다음 가능 상태
created 요청이 생성됨 pending_verification, cancelled
pending_verification 신원 확인 대기 중 verified, cancelled
verified 신원 확인 완료 legal_review
legal_review 법적 검토 진행 중 processing, rejected
processing 삭제 작업 진행 중 completed, failed
completed 삭제 완료 (종료 상태)
rejected 법적 사유로 거부됨 (종료 상태)
failed 기술적 오류로 실패 processing (재시도)
cancelled 사용자가 취소함 (종료 상태)

5.5 Webhook 콜백

비동기 처리를 위해 요청 생성 시 callback_url을 제공하면, 상태 변경 시 자동으로 알림을 받을 수 있습니다.

콜백 페이로드

POST https://your-app.com/rtbf/callback
Content-Type: application/json
X-WIA-Signature: sha256=abc123... (HMAC 서명)

{
  "event": "request.completed",
  "timestamp": "2025-01-30T15:30:00Z",
  "data": {
    "request_id": "rtbf_20250101_abc123",
    "status": "completed",
    "completion_details": {
      "systems_processed": 5,
      "records_deleted": 1523,
      "backups_cleaned": 3
    }
  }
}

콜백 이벤트

  • request.created: 요청 생성됨
  • request.verified: 신원 확인됨
  • request.processing: 처리 시작됨
  • request.completed: 삭제 완료됨
  • request.failed: 실패함
  • request.rejected: 거부됨

서명 검증 (보안)

import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = 'sha256=' + hmac.update(payload).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
}

5.6 GraphQL API (선택 사항)

REST API 외에도 더 유연한 쿼리를 위해 GraphQL을 지원할 수 있습니다.

GraphQL 스키마

type Query {
  rtbfRequest(id: ID!): RTBFRequest
  rtbfRequests(
    page: Int = 1
    limit: Int = 20
    status: RTBFStatus
    email: String
  ): RTBFRequestConnection
}

type Mutation {
  createRTBFRequest(input: CreateRTBFRequestInput!): RTBFRequest
  verifyRTBFRequest(id: ID!, code: String!): RTBFRequest
  cancelRTBFRequest(id: ID!): RTBFRequest
}

type RTBFRequest {
  id: ID!
  status: RTBFStatus!
  createdAt: DateTime!
  dataSubject: DataSubject!
  progress: Progress
  timeline: [TimelineEvent!]!
}

enum RTBFStatus {
  CREATED
  PENDING_VERIFICATION
  VERIFIED
  LEGAL_REVIEW
  PROCESSING
  COMPLETED
  REJECTED
  FAILED
  CANCELLED
}

쿼리 예시

query GetRequestDetails {
  rtbfRequest(id: "rtbf_20250101_abc123") {
    id
    status
    createdAt
    dataSubject {
      email
    }
    progress {
      totalSystems
      completedSystems
      percentage
    }
    timeline {
      event
      timestamp
      system
    }
  }
}

뮤테이션 예시

mutation CreateRequest {
  createRTBFRequest(input: {
    requestType: DELETION
    dataSubject: {
      email: "user@example.com"
      identifiers: [
        {type: "user_id", value: "12345"}
      ]
    }
    legalBasis: "GDPR_Article_17_1a"
    scope: {
      dataCategories: ["personal_data"]
      includeBackups: true
    }
  }) {
    id
    status
  }
}

5.7 에러 처리

표준 에러 응답

400 Bad Request

{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "The request is missing required fields",
    "details": [
      {
        "field": "data_subject.email",
        "issue": "Required field is missing"
      }
    ],
    "documentation_url": "https://docs.wia.org/rtbf/errors#INVALID_REQUEST"
  }
}

에러 코드

HTTP 코드 설명
400 INVALID_REQUEST 요청 형식 오류
401 UNAUTHORIZED 인증 실패
403 FORBIDDEN 권한 없음
404 NOT_FOUND 요청을 찾을 수 없음
409 DUPLICATE_REQUEST 중복 요청
422 VALIDATION_ERROR 검증 실패
429 RATE_LIMIT_EXCEEDED 요청 한도 초과
500 INTERNAL_ERROR 서버 오류
503 SERVICE_UNAVAILABLE 일시적 서비스 중단

5.8 SDK 및 클라이언트 라이브러리

TypeScript/JavaScript SDK

import { WIARTBFClient } from '@wia/rtbf-sdk';

const client = new WIARTBFClient({
  apiKey: 'wia_api_key_abc123',
  baseUrl: 'https://api.example.com/wia/rtbf/v1'
});

// 요청 생성
const request = await client.createRequest({
  requestType: 'deletion',
  dataSubject: {
    email: 'user@example.com',
    identifiers: [{ type: 'user_id', value: '12345' }]
  },
  legalBasis: 'GDPR_Article_17_1a',
  scope: {
    dataCategories: ['personal_data'],
    includeBackups: true
  }
});

console.log(`Request created: ${request.id}`);

// 상태 확인
const status = await client.getRequest(request.id);
console.log(`Status: ${status.status}`);

Python SDK

from wia_rtbf import RTBFClient

client = RTBFClient(
    api_key='wia_api_key_abc123',
    base_url='https://api.example.com/wia/rtbf/v1'
)

# 요청 생성
request = client.create_request(
    request_type='deletion',
    data_subject={
        'email': 'user@example.com',
        'identifiers': [{'type': 'user_id', 'value': '12345'}]
    },
    legal_basis='GDPR_Article_17_1a',
    scope={
        'data_categories': ['personal_data'],
        'include_backups': True
    }
)

print(f'Request created: {request.id}')

# 상태 확인
status = client.get_request(request.id)
print(f'Status: {status.status}')

5.9 다음 단계

이 장에서는 WIA-LEG-009 Phase 2의 API 인터페이스를 상세히 살펴보았습니다. 다음 장에서는 블록체인을 사용한 암호학적 삭제 검증인 Phase 3를 다룹니다.