API 파일 업로드는 개발자가 AI 비디오 생성, 이미지 처리 등의 API를 호출할 때 자주 접하게 되는 기술적 요구사항입니다. 본문에서는 multipart/form-data 인코딩 방식의 작동 원리를 체계적으로 설명하고, Sora 2 이미지 투 비디오(Image-to-Video) API를 예로 들어 API 파일 업로드의 핵심 기술을 습득할 수 있도록 도와드립니다.
핵심 가치: 이 글을 읽고 나면 multipart/form-data의 기본 메커니즘을 완벽히 이해하고, curl -F 명령어를 사용하여 파일을 업로드하는 방법을 배우며, Sora 2와 같은 AI API의 이미지 업로드 기능을 독립적으로 구현할 수 있게 됩니다.

API 파일 업로드 핵심 지식
코드에 깊이 들어가기 전에, 왜 API 파일 업로드에 특수한 인코딩 방식이 필요한지 이해해야 합니다.
왜 multipart/form-data가 필요한가요?
API를 통해 일반적인 텍스트 데이터를 보낼 때는 간단한 application/x-www-form-urlencoded 인코딩을 사용할 수 있습니다. 하지만 이 방식은 파일을 처리할 때 심각한 문제가 발생합니다.
| 인코딩 유형 | 활용 사례 | 파일 처리 능력 | 효율성 |
|---|---|---|---|
application/x-www-form-urlencoded |
단순 키-값 쌍 | ❌ 부적합 | 바이너리는 URL 이스케이프가 필요하며 효율이 낮음 |
application/json |
구조화된 데이터 | ⚠️ Base64 인코딩 필요 | 크기가 33% 증가 |
multipart/form-data |
파일 업로드 | ✅ 네이티브 지원 | 인코딩 불필요, 고효율 |
multipart/form-data는 1998년 RFC 2388 표준으로 제안된 방안으로, HTTP 프로토콜에서 텍스트와 바이너리 데이터를 혼합하여 전송하는 문제를 전문적으로 해결합니다.
multipart/form-data 작동 원리
multipart/form-data의 핵심 아이디어는 하나의 HTTP 요청 본문을 여러 개의 독립적인 「부분」(parts)으로 나누는 것입니다. 각 부분은 자신만의 콘텐츠 유형을 가질 수 있습니다.

데이터 구조详解
전형적인 multipart/form-data 요청은 다음과 같은 구조를 포함합니다:
POST /v1/videos HTTP/1.1
Host: api.apiyi.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="prompt"
She turns around and smiles
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="model"
sora-2-pro
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="input_reference"; filename="sample.jpeg"
Content-Type: image/jpeg
[바이너리 이미지 데이터]
------WebKitFormBoundary7MA4YWxk--
| 구성 요소 | 역할 | 예시 |
|---|---|---|
| Boundary | 각 데이터 부분을 구분하는 고유 식별자 | ----WebKitFormBoundary7MA4YWxk |
| Content-Disposition | 해당 부분의 메타데이터를 설명 | form-data; name="prompt" |
| Content-Type | 해당 부분의 MIME 유형 | image/jpeg |
| Body | 실제 데이터 내용 | 텍스트 또는 바이너리 데이터 |
🎯 기술 요점: Boundary는 요청 본문에 나타나지 않는 고유한 문자열이어야 합니다. 서버는 이 boundary를 통해 각 데이터 부분을 해석하고 분리합니다.
curl -F 명령어 상세 설명: API 파일 업로드 실전
curl은 가장 널리 사용되는 명령줄 HTTP 클라이언트 도구예요. 그중 -F 파라미터는 multipart/form-data 요청을 처리하는 데 특화되어 있죠.
curl -F 기본 문법
curl -F "字段名=值" URL
curl -F "文件字段=@本地文件路径" URL
| 파라미터 형식 | 설명 | 예시 |
|---|---|---|
-F "key=value" |
일반 텍스트 필드 전송 | -F "prompt=Hello" |
-F "key=@file" |
로컬 파일 업로드 | -F "[email protected]" |
-F "key=@file;type=mime" |
파일 MIME 타입 지정 | -F "[email protected];type=image/jpeg" |
-F "key=@file;filename=new.jpg" |
업로드 파일 이름 사용자 정의 | -F "[email protected];filename=upload.jpg" |
curl -F와 다른 파라미터의 차이점
많은 개발자분이 -F, -d, 그리고 -X POST 사용법을 헷갈려하시곤 해요.
# ❌ 错误: -d 用于 x-www-form-urlencoded,不适合文件上传
curl -X POST -d "[email protected]" https://api.example.com/upload
# ❌ 错误: 手动指定 Content-Type 但使用 -d
curl -X POST -H "Content-Type: multipart/form-data" -d "..." https://api.example.com/upload
# ✅ 正确: 使用 -F 自动设置正确的 Content-Type 和 boundary
curl -F "[email protected]" https://api.example.com/upload
기술 설명:
-F를 사용하면 curl이 자동으로 다음과 같은 작업을 수행해요.
- 요청 방식을 POST로 설정
Content-Type: multipart/form-data설정- 고유한 boundary(경계선) 생성
- RFC 표준에 맞춰 요청 본문(Body) 포맷팅
Sora 2 API 파일 업로드 실전
Sora 2는 OpenAI에서 출시한 비디오 생성 모델로, API를 통해 참조 이미지를 업로드하여 비디오를 생성하는 기능을 지원해요. 이는 multipart/form-data가 활용되는 대표적인 사례입니다.
Sora 2 이미지 기반 비디오 생성 API 파라미터
| 파라미터 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
prompt |
string | ✅ | 비디오 묘사 텍스트(프롬프트) |
model |
string | ❌ | 모델 선택: sora-2 또는 sora-2-pro |
size |
string | ❌ | 해상도: 1280x720, 720x1280, 1024x1792, 1792x1024 |
seconds |
integer | ❌ | 길이: 4, 8, 12 초 |
input_reference |
file | ❌ | 참조 이미지, 비디오의 첫 프레임으로 사용 |

Sora 2 모델 비교
| 특징 | sora-2 | sora-2-pro |
|---|---|---|
| 생성 품질 | 양호 | 탁월 |
| 렌더링 속도 | 빠름 | 느림 |
| 활용 사례 | 빠른 프로토타이핑, PoC | 프로덕션급 출력 |
| 가격 | 표준 | 높음 |
| 사용 가능 플랫폼 | APIYI(apiyi.com), 공식 API | APIYI(apiyi.com), 공식 API |
Sora 2 파일 업로드 전체 예시
다음은 curl을 사용하여 Sora 2 API를 호출하고 이미지 기반 비디오를 생성하는 전체 예시예요.
curl -X POST "https://api.apiyi.com/v1/videos" \
-H "Authorization: Bearer $APIYI_KEY" \
-H "Content-Type: multipart/form-data" \
-F prompt="She turns around and smiles, then slowly walks out of the frame." \
-F model="sora-2-pro" \
-F size="1280x720" \
-F seconds="8" \
-F input_reference="@sample_720p.jpeg;type=image/jpeg"
명령어 분석
| 부분 | 설명 |
|---|---|
curl -X POST |
POST 요청 방식 지정 |
"https://api.apiyi.com/v1/videos" |
APIYI Sora 2 비디오 생성 엔드포인트 |
-H "Authorization: Bearer $APIYI_KEY" |
환경 변수를 사용하여 API 키 전달 |
-H "Content-Type: multipart/form-data" |
콘텐츠 유형 선언 (curl -F 사용 시 자동 추가됨) |
-F prompt="..." |
비디오 묘사 프롬프트 |
-F model="sora-2-pro" |
고품질 모델 선택 |
-F size="1280x720" |
가로형 720p 해상도 |
-F seconds="8" |
8초 길이 |
-F input_reference="@sample_720p.jpeg;type=image/jpeg" |
참조 이미지 업로드 |
🚀 빠른 시작: APIYI(apiyi.com) 플랫폼을 사용하면 Sora 2 API를 빠르게 테스트해 볼 수 있어요. 복잡한 설정 없이 바로 사용할 수 있는 API 인터페이스를 제공하여 통합이 매우 간편하답니다.
이미지 업로드 주의사항
Sora 2 API로 참조 이미지를 업로드할 때는 다음 사항을 주의해 주세요.
| 요구 사항 | 설명 |
|---|---|
| 해상도 일치 | 이미지 해상도는 대상 비디오의 size 파라미터와 일치해야 합니다. |
| 지원 형식 | image/jpeg, image/png, image/webp |
| 파일 크기 | 10MB 이내 권장 |
| 이미지 품질 | 선명하고 구도가 완벽한 이미지가 더 좋은 효과를 냅니다. |
Python으로 multipart/form-data 업로드 구현하기
curl 외에도 실제 개발에서는 프로그래밍 언어를 사용하여 파일을 업로드하는 경우가 더 많아요. 아래는 Python을 이용한 구현 방법입니다.
아주 간단한 예시
import requests
# APIYI 통합 인터페이스 사용
url = "https://api.apiyi.com/v1/videos"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
# multipart 데이터 준비
files = {
"input_reference": ("sample.jpeg", open("sample_720p.jpeg", "rb"), "image/jpeg")
}
data = {
"prompt": "She turns around and smiles, then slowly walks out of the frame.",
"model": "sora-2-pro",
"size": "1280x720",
"seconds": "8"
}
response = requests.post(url, headers=headers, data=data, files=files)
print(response.json())
전체 코드 확인하기 (오류 처리 및 폴링 포함)
import requests
import time
import os
class Sora2Client:
"""Sora 2 API 클라이언트 - multipart/form-data 파일 업로드 지원"""
def __init__(self, api_key: str, base_url: str = "https://api.apiyi.com/v1"):
self.api_key = api_key
self.base_url = base_url
self.headers = {"Authorization": f"Bearer {api_key}"}
def create_video(
self,
prompt: str,
model: str = "sora-2",
size: str = "1280x720",
seconds: int = 8,
input_reference: str = None
) -> dict:
"""
비디오 생성 작업 생성
Args:
prompt: 비디오 설명
model: 모델 선택 (sora-2 또는 sora-2-pro)
size: 해상도
seconds: 재생 시간 (4, 8, 12)
input_reference: 참고 이미지 경로 (선택 사항)
Returns:
작업 정보 딕셔너리
"""
url = f"{self.base_url}/videos"
data = {
"prompt": prompt,
"model": model,
"size": size,
"seconds": str(seconds)
}
files = None
if input_reference and os.path.exists(input_reference):
# 파일 확장자에 따라 MIME 타입 결정
ext = os.path.splitext(input_reference)[1].lower()
mime_types = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".webp": "image/webp"
}
mime_type = mime_types.get(ext, "application/octet-stream")
files = {
"input_reference": (
os.path.basename(input_reference),
open(input_reference, "rb"),
mime_type
)
}
try:
response = requests.post(
url,
headers=self.headers,
data=data,
files=files,
timeout=30
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {"error": str(e)}
finally:
if files and "input_reference" in files:
files["input_reference"][1].close()
def get_video_status(self, video_id: str) -> dict:
"""비디오 생성 상태 조회"""
url = f"{self.base_url}/videos/{video_id}"
response = requests.get(url, headers=self.headers, timeout=30)
return response.json()
def wait_for_completion(self, video_id: str, poll_interval: int = 10) -> dict:
"""폴링 방식으로 비디오 생성 완료 대기"""
while True:
status = self.get_video_status(video_id)
if status.get("status") in ["completed", "failed"]:
return status
print(f"Status: {status.get('status')}... waiting {poll_interval}s")
time.sleep(poll_interval)
# 사용 예시
if __name__ == "__main__":
client = Sora2Client(api_key=os.getenv("APIYI_KEY"))
# 이미지 기반 비디오 생성 작업 생성
result = client.create_video(
prompt="She turns around and smiles, then slowly walks out of the frame.",
model="sora-2-pro",
size="1280x720",
seconds=8,
input_reference="sample_720p.jpeg"
)
if "id" in result:
print(f"Task created: {result['id']}")
final_result = client.wait_for_completion(result["id"])
print(f"Video URL: {final_result.get('video_url')}")
else:
print(f"Error: {result}")
권장 사항: APIYI(apiyi.com)에서 무료 테스트 크레딧을 받아 이미지 기반 비디오 생성 기능을 빠르게 검증해 보세요.
requests 라이브러리의 multipart 처리
Python requests 라이브러리에서 multipart/form-data를 처리할 때의 핵심 포인트는 다음과 같아요.
| 매개변수 | 용도 | 설명 |
|---|---|---|
data |
일반 폼 필드 | 딕셔너리 형식: {"key": "value"} |
files |
파일 필드 | 튜플 형식: {"name": (filename, file_obj, content_type)} |
⚠️ 주의:
data와files매개변수를 동시에 사용하면, requests가 자동으로 올바른Content-Type과 boundary를 설정합니다. 따라서 개발자가 수동으로 지정할 필요가 없습니다.
JavaScript/Node.js 구현 방법
브라우저 환경 (FormData API)
const formData = new FormData();
formData.append('prompt', 'She turns around and smiles');
formData.append('model', 'sora-2-pro');
formData.append('size', '1280x720');
formData.append('seconds', '8');
formData.append('input_reference', fileInput.files[0]);
fetch('https://api.apiyi.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
// 주의: Content-Type을 수동으로 설정하지 마세요.
},
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
Node.js 환경
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');
const form = new FormData();
form.append('prompt', 'She turns around and smiles');
form.append('model', 'sora-2-pro');
form.append('size', '1280x720');
form.append('seconds', '8');
form.append('input_reference', fs.createReadStream('sample_720p.jpeg'), {
contentType: 'image/jpeg'
});
axios.post('https://api.apiyi.com/v1/videos', form, {
headers: {
...form.getHeaders(),
'Authorization': 'Bearer YOUR_API_KEY'
}
})
.then(response => console.log(response.data));
💡 핵심 팁: 브라우저에서
FormData를 사용할 때는Content-Type헤더를 수동으로 설정하지 마세요. 브라우저가 자동으로 올바른 boundary 매개변수를 추가해 줍니다.
multipart/form-data 일반적인 문제 해결
업로드 실패의 일반적인 원인
| 문제 | 증상 | 해결 방법 |
|---|---|---|
| boundary 누락 | 서버에서 400 에러 반환 | Content-Type을 수동으로 설정하지 말고, 도구가 자동으로 생성하게 하세요. |
| MIME 타입 오류 | 파일 거부됨 | ;type=image/jpeg와 같이 타입을 명시적으로 지정하세요. |
| 파일 경로 오류 | 파일을 찾을 수 없음 | @ 뒤의 경로가 올바른지 확인하세요. 상대 경로와 절대 경로를 모두 지원합니다. |
| 해상도 불일치 | Sora API 오류 발생 | 이미지 해상도는 size 파라미터와 반드시 일치해야 합니다. |
| 파일 용량 초과 | 타임아웃 또는 거부됨 | 이미지를 압축하거나 분할 업로드를 이용하세요. |
디버깅 팁
curl의 -v 파라미터를 사용하면 전체 요청 과정을 상세히 확인할 수 있어요:
curl -v -F "[email protected]" https://api.example.com/upload
이 명령어를 통해 다음 내용들을 확인할 수 있습니다:
- 요청 헤더 (자동 생성된 Content-Type 및 boundary 포함)
- 요청 본문(body) 구조
- 서버 응답 메시지
자주 묻는 질문 (FAQ)
Q1: multipart/form-data와 Base64 인코딩 중 어느 것이 더 좋은가요?
파일 업로드에는 multipart/form-data 방식이 더 적합합니다. Base64 인코딩은 파일 크기를 약 33% 정도 증가시켜 네트워크 전송 시간과 서버의 처리 부담을 가중시킵니다. 반면 multipart/form-data는 바이너리 데이터를 직접 전송하기 때문에 효율성이 훨씬 높습니다.
다만 WebSocket이나 단일 필드 JSON API를 사용하는 경우처럼 특정 상황에서는 Base64가 유일한 선택지일 수 있습니다. APIYI apiyi.com 플랫폼을 통해 API를 호출하실 때는 가급적 multipart/form-data 방식을 사용하여 더 쾌적한 성능을 경험해 보세요.
Q2: 왜 curl -F를 이용한 업로드가 실패할까요?
주요 원인은 다음과 같습니다:
- 파일 경로 문제:
@기호 뒤에 파일 경로가 정확하게 입력되었는지 확인해 보세요. - 권한 문제: 해당 파일을 읽을 수 있는 권한이 있는지 체크해 보세요.
- MIME 타입: 일부 API는 정확한 content-type 지정을 필수적으로 요구하기도 합니다.
문제가 잘 해결되지 않는다면 먼저 APIYI apiyi.com에서 제공하는 테스트 환경을 통해 요청 형식을 검증해 보시는 것을 추천드려요. 플랫폼에서 제공하는 상세한 오류 메시지를 통해 문제를 빠르게 파악할 수 있습니다.
Q3: Sora 2 API는 어떤 이미지 형식을 지원하나요?
Sora 2 API의 input_reference 기능은 다음 이미지 형식들을 지원합니다:
- JPEG (
.jpg,.jpeg): 높은 압축률로 권장되는 형식입니다. - PNG (
.png): 투명 채널을 지원합니다. - WebP (
.webp): 용량이 작으면서도 효율적인 최신 형식입니다.
이미지 해상도는 생성하려는 비디오의 size 파라미터와 일치해야 한다는 점에 유의하세요. 예를 들어 비디오 해상도를 1280x720으로 설정했다면, 참조 이미지 역시 1280×720이어야 합니다.
Q4: 대용량 파일 업로드는 어떻게 처리하는 게 좋을까요?
대용량 파일을 업로드할 때는 다음과 같은 방법들을 고려해 보세요:
- 분할 업로드: 파일을 작은 조각(chunk)으로 나누어 순차적으로 업로드합니다.
- 압축 최적화: 화질이나 품질을 적절히 유지하는 선에서 파일 용량을 압축합니다.
- 이어올리기 (Resumable Upload): 네트워크 문제로 업로드가 실패했을 때, 처음부터 다시 하지 않고 중단된 지점부터 이어 올릴 수 있도록 구현합니다.
multipart/form-data는 스트리밍 전송을 지원하기 때문에 서버가 데이터를 받는 동시에 처리할 수 있어 대용량 파일 시나리오에도 매우 적합한 방식입니다.
요약
본문에서는 API 파일 업로드의 핵심 기술인 multipart/form-data에 대해 자세히 알아보았습니다.
핵심 지식 복습:
| 핵심 요점 | 설명 |
|---|---|
| 인코딩 원리 | boundary로 여러 파트의 데이터를 구분하며, 각 파트는 독립적인 Content-Type을 가집니다. |
| curl -F 명령 | -F "key=value"는 텍스트를 전송하고, -F "key=@file"은 파일을 업로드합니다. |
| Sora 2 실전 | input_reference 파라미터로 참조 이미지를 업로드하며, 해상도가 일치해야 합니다. |
| 다양한 언어 구현 | Python requests / JavaScript FormData 등 |
| 디버깅 팁 | curl -v를 사용하여 전체 요청 내용을 상세히 확인합니다. |
multipart/form-data를 숙달하는 것은 AI API 개발의 필수적인 기초 역량입니다. Sora 2 영상 생성, GPT-4 Vision 이미지 이해 등 파일 업로드가 필요한 모든 API의 핵심 원리는 결국 하나로 통하기 때문입니다.
APIYI(apiyi.com)를 통해 파일 업로드 기능을 빠르게 검증해 보세요. 통합된 API 인터페이스와 상세한 기술 지원을 직접 경험하실 수 있습니다.
작성자: APIYI Team | AI 대규모 언어 모델 API 기술 공유 전문
기술 교류: apiyi.com을 방문하여 더 많은 API 개발 리소스를 확인하세요.
참고 자료
-
RFC 2388: multipart/form-data 표준 명세
- 링크:
tools.ietf.org/html/rfc2388
- 링크:
-
curl 공식 문서: Multipart Formposts
- 링크:
everything.curl.dev/http/post/multipart
- 링크:
-
MDN Web Docs: FormData 객체 사용하기
- 링크:
developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects
- 링크:
-
OpenAI Sora API 문서: Video Generation Guide
- 링크:
platform.openai.com/docs/guides/video-generation
- 링크:
