o2o-castad-backend/docs/api/social_api_spec.json

602 lines
20 KiB
JSON

{
"info": {
"title": "Social Media Integration API",
"version": "1.0.0",
"description": "소셜 미디어 연동 및 영상 업로드 API 명세서",
"baseUrl": "http://localhost:8000"
},
"authentication": {
"type": "Bearer Token",
"header": "Authorization",
"format": "Bearer {access_token}",
"description": "카카오 로그인 후 발급받은 JWT access_token 사용"
},
"endpoints": {
"oauth": {
"connect": {
"name": "소셜 계정 연동 시작",
"method": "GET",
"url": "/social/oauth/{platform}/connect",
"description": "OAuth 인증 URL을 생성합니다. 반환된 auth_url로 사용자를 리다이렉트하세요.",
"authentication": true,
"pathParameters": {
"platform": {
"type": "string",
"enum": ["youtube"],
"description": "연동할 플랫폼 (현재 youtube만 지원)"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=xxx&redirect_uri=xxx&response_type=code&scope=xxx&state=xxx",
"state": "abc123xyz789",
"platform": "youtube"
}
},
"error": {
"401": {
"detail": "인증이 필요합니다."
},
"422": {
"detail": "지원하지 않는 플랫폼입니다."
}
}
},
"frontendAction": "auth_url로 window.location.href 또는 새 창으로 리다이렉트"
},
"callback": {
"name": "OAuth 콜백 (백엔드 자동 처리)",
"method": "GET",
"url": "/social/oauth/{platform}/callback",
"description": "Google에서 자동으로 호출됩니다. 프론트엔드에서 직접 호출하지 마세요.",
"authentication": false,
"note": "연동 성공 시 프론트엔드의 /social/connect/success 페이지로 리다이렉트됩니다.",
"redirectOnSuccess": {
"url": "{PROJECT_DOMAIN}/social/connect/success",
"queryParams": {
"platform": "youtube",
"account_id": 1,
"channel_name": "My YouTube Channel",
"profile_image": "https://yt3.ggpht.com/..."
},
"example": "/social/connect/success?platform=youtube&account_id=1&channel_name=My+YouTube+Channel&profile_image=https%3A%2F%2Fyt3.ggpht.com%2F..."
},
"redirectOnError": {
"url": "{PROJECT_DOMAIN}/social/connect/error",
"queryParams": {
"platform": "youtube",
"error": "에러 메시지"
}
}
},
"getAccounts": {
"name": "연동된 계정 목록 조회",
"method": "GET",
"url": "/social/oauth/accounts",
"description": "현재 사용자가 연동한 모든 소셜 계정 목록을 반환합니다.",
"authentication": true,
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"accounts": [
{
"id": 1,
"platform": "youtube",
"platform_user_id": "UC1234567890abcdef",
"platform_username": "@mychannel",
"display_name": "My YouTube Channel",
"profile_image_url": "https://yt3.ggpht.com/...",
"is_active": true,
"connected_at": "2024-01-15T12:00:00",
"platform_data": {
"channel_id": "UC1234567890abcdef",
"channel_title": "My YouTube Channel",
"subscriber_count": "1000",
"video_count": "50"
}
}
],
"total": 1
}
}
}
},
"getAccountByPlatform": {
"name": "특정 플랫폼 연동 계정 조회",
"method": "GET",
"url": "/social/oauth/accounts/{platform}",
"description": "특정 플랫폼에 연동된 계정 정보를 반환합니다.",
"authentication": true,
"pathParameters": {
"platform": {
"type": "string",
"enum": ["youtube"],
"description": "조회할 플랫폼"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"id": 1,
"platform": "youtube",
"platform_user_id": "UC1234567890abcdef",
"platform_username": "@mychannel",
"display_name": "My YouTube Channel",
"profile_image_url": "https://yt3.ggpht.com/...",
"is_active": true,
"connected_at": "2024-01-15T12:00:00",
"platform_data": {
"channel_id": "UC1234567890abcdef",
"channel_title": "My YouTube Channel",
"subscriber_count": "1000",
"video_count": "50"
}
}
},
"error": {
"404": {
"detail": "youtube 플랫폼에 연동된 계정이 없습니다."
}
}
}
},
"disconnect": {
"name": "소셜 계정 연동 해제",
"method": "DELETE",
"url": "/social/oauth/{platform}/disconnect",
"description": "소셜 미디어 계정 연동을 해제합니다.",
"authentication": true,
"pathParameters": {
"platform": {
"type": "string",
"enum": ["youtube"],
"description": "연동 해제할 플랫폼"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"success": true,
"message": "youtube 계정 연동이 해제되었습니다."
}
},
"error": {
"404": {
"detail": "youtube 플랫폼에 연동된 계정이 없습니다."
}
}
}
}
},
"upload": {
"create": {
"name": "소셜 플랫폼에 영상 업로드 요청",
"method": "POST",
"url": "/social/upload",
"description": "영상을 소셜 미디어 플랫폼에 업로드합니다. 백그라운드에서 처리됩니다.",
"authentication": true,
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"Content-Type": "application/json"
},
"body": {
"video_id": {
"type": "integer",
"required": true,
"description": "업로드할 영상 ID (Video 테이블의 id)",
"example": 123
},
"platform": {
"type": "string",
"required": true,
"enum": ["youtube"],
"description": "업로드할 플랫폼",
"example": "youtube"
},
"title": {
"type": "string",
"required": true,
"maxLength": 100,
"description": "영상 제목",
"example": "나의 첫 영상"
},
"description": {
"type": "string",
"required": false,
"maxLength": 5000,
"description": "영상 설명",
"example": "이 영상은 테스트 영상입니다."
},
"tags": {
"type": "array",
"required": false,
"items": "string",
"description": "태그 목록",
"example": ["여행", "vlog", "일상"]
},
"privacy_status": {
"type": "string",
"required": false,
"enum": ["public", "unlisted", "private"],
"default": "private",
"description": "공개 상태",
"example": "private"
},
"platform_options": {
"type": "object",
"required": false,
"description": "플랫폼별 추가 옵션",
"example": {
"category_id": "22"
}
}
},
"example": {
"video_id": 123,
"platform": "youtube",
"title": "나의 첫 영상",
"description": "이 영상은 테스트 영상입니다.",
"tags": ["여행", "vlog"],
"privacy_status": "private",
"platform_options": {
"category_id": "22"
}
}
},
"response": {
"success": {
"status": 200,
"body": {
"success": true,
"upload_id": 456,
"platform": "youtube",
"status": "pending",
"message": "업로드 요청이 접수되었습니다."
}
},
"error": {
"404_video": {
"detail": "영상을 찾을 수 없습니다."
},
"404_account": {
"detail": "youtube 플랫폼에 연동된 계정이 없습니다."
},
"400": {
"detail": "영상이 아직 준비되지 않았습니다."
}
}
},
"youtubeCategoryIds": {
"1": "Film & Animation",
"2": "Autos & Vehicles",
"10": "Music",
"15": "Pets & Animals",
"17": "Sports",
"19": "Travel & Events",
"20": "Gaming",
"22": "People & Blogs (기본값)",
"23": "Comedy",
"24": "Entertainment",
"25": "News & Politics",
"26": "Howto & Style",
"27": "Education",
"28": "Science & Technology",
"29": "Nonprofits & Activism"
}
},
"getStatus": {
"name": "업로드 상태 조회",
"method": "GET",
"url": "/social/upload/{upload_id}/status",
"description": "특정 업로드 작업의 상태를 조회합니다. 폴링으로 상태를 확인하세요.",
"authentication": true,
"pathParameters": {
"upload_id": {
"type": "integer",
"description": "업로드 ID"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"upload_id": 456,
"video_id": 123,
"platform": "youtube",
"status": "completed",
"upload_progress": 100,
"title": "나의 첫 영상",
"platform_video_id": "dQw4w9WgXcQ",
"platform_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"error_message": null,
"retry_count": 0,
"created_at": "2024-01-15T12:00:00",
"uploaded_at": "2024-01-15T12:05:00"
}
},
"error": {
"404": {
"detail": "업로드 정보를 찾을 수 없습니다."
}
}
},
"statusValues": {
"pending": "업로드 대기 중",
"uploading": "업로드 진행 중 (upload_progress 확인)",
"processing": "플랫폼에서 처리 중",
"completed": "업로드 완료 (platform_url 사용 가능)",
"failed": "업로드 실패 (error_message 확인)",
"cancelled": "업로드 취소됨"
},
"pollingRecommendation": {
"interval": "3초",
"maxAttempts": 100,
"stopConditions": ["completed", "failed", "cancelled"]
}
},
"getHistory": {
"name": "업로드 이력 조회",
"method": "GET",
"url": "/social/upload/history",
"description": "사용자의 소셜 미디어 업로드 이력을 조회합니다.",
"authentication": true,
"queryParameters": {
"platform": {
"type": "string",
"required": false,
"enum": ["youtube"],
"description": "플랫폼 필터"
},
"status": {
"type": "string",
"required": false,
"enum": ["pending", "uploading", "processing", "completed", "failed", "cancelled"],
"description": "상태 필터"
},
"page": {
"type": "integer",
"required": false,
"default": 1,
"description": "페이지 번호"
},
"size": {
"type": "integer",
"required": false,
"default": 20,
"min": 1,
"max": 100,
"description": "페이지 크기"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
},
"exampleUrl": "/social/upload/history?platform=youtube&status=completed&page=1&size=20"
},
"response": {
"success": {
"status": 200,
"body": {
"items": [
{
"upload_id": 456,
"video_id": 123,
"platform": "youtube",
"status": "completed",
"title": "나의 첫 영상",
"platform_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"created_at": "2024-01-15T12:00:00",
"uploaded_at": "2024-01-15T12:05:00"
}
],
"total": 1,
"page": 1,
"size": 20
}
}
}
},
"retry": {
"name": "업로드 재시도",
"method": "POST",
"url": "/social/upload/{upload_id}/retry",
"description": "실패한 업로드를 재시도합니다.",
"authentication": true,
"pathParameters": {
"upload_id": {
"type": "integer",
"description": "업로드 ID"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"success": true,
"upload_id": 456,
"platform": "youtube",
"status": "pending",
"message": "업로드 재시도가 요청되었습니다."
}
},
"error": {
"400": {
"detail": "실패하거나 취소된 업로드만 재시도할 수 있습니다."
},
"404": {
"detail": "업로드 정보를 찾을 수 없습니다."
}
}
}
},
"cancel": {
"name": "업로드 취소",
"method": "DELETE",
"url": "/social/upload/{upload_id}",
"description": "대기 중인 업로드를 취소합니다.",
"authentication": true,
"pathParameters": {
"upload_id": {
"type": "integer",
"description": "업로드 ID"
}
},
"request": {
"headers": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"response": {
"success": {
"status": 200,
"body": {
"success": true,
"message": "업로드가 취소되었습니다."
}
},
"error": {
"400": {
"detail": "대기 중인 업로드만 취소할 수 있습니다."
},
"404": {
"detail": "업로드 정보를 찾을 수 없습니다."
}
}
}
}
}
},
"frontendPages": {
"required": [
{
"path": "/social/connect/success",
"description": "OAuth 연동 성공 후 리다이렉트되는 페이지",
"queryParams": {
"platform": "플랫폼명 (youtube)",
"account_id": "연동된 계정 ID",
"channel_name": "YouTube 채널 이름 (URL 인코딩됨)",
"profile_image": "프로필 이미지 URL (URL 인코딩됨)"
},
"action": "연동 성공 메시지 표시, 채널 정보 즉시 표시 가능, 이후 GET /social/oauth/accounts 호출로 전체 목록 갱신"
},
{
"path": "/social/connect/error",
"description": "OAuth 연동 실패 시 리다이렉트되는 페이지",
"queryParams": {
"platform": "플랫폼명 (youtube)",
"error": "에러 메시지 (URL 인코딩됨)"
},
"action": "에러 메시지 표시 및 재시도 옵션 제공"
}
],
"recommended": [
{
"path": "/settings/social",
"description": "소셜 계정 관리 페이지",
"features": ["연동된 계정 목록", "연동/해제 버튼", "업로드 이력"]
}
]
},
"flowExamples": {
"connectYouTube": {
"description": "YouTube 계정 연동 플로우",
"steps": [
{
"step": 1,
"action": "GET /social/oauth/youtube/connect 호출",
"result": "auth_url 반환"
},
{
"step": 2,
"action": "window.location.href = auth_url",
"result": "Google 로그인 페이지로 이동"
},
{
"step": 3,
"action": "사용자가 권한 승인",
"result": "백엔드 콜백 URL로 자동 리다이렉트"
},
{
"step": 4,
"action": "백엔드가 토큰 교환 후 프론트엔드로 리다이렉트",
"result": "/social/connect/success?platform=youtube&account_id=1&channel_name=My+Channel&profile_image=https%3A%2F%2F..."
},
{
"step": 5,
"action": "URL 파라미터에서 채널 정보 추출하여 즉시 표시",
"code": "const params = new URLSearchParams(window.location.search); const channelName = params.get('channel_name'); const profileImage = params.get('profile_image');"
},
{
"step": 6,
"action": "GET /social/oauth/accounts 호출로 전체 계정 목록 갱신",
"result": "연동된 계정 정보 표시"
}
]
},
"uploadVideo": {
"description": "YouTube 영상 업로드 플로우",
"steps": [
{
"step": 1,
"action": "POST /social/upload 호출",
"request": {
"video_id": 123,
"platform": "youtube",
"title": "영상 제목",
"privacy_status": "private"
},
"result": "upload_id 반환"
},
{
"step": 2,
"action": "GET /social/upload/{upload_id}/status 폴링 (3초 간격)",
"result": "status, upload_progress 확인"
},
{
"step": 3,
"action": "status === 'completed' 확인",
"result": "platform_url로 YouTube 링크 표시"
}
],
"pollingCode": "setInterval(() => checkUploadStatus(uploadId), 3000)"
}
}
}