파일을 받는 엔드포인트를 구축했습니다. 사용자가 프로필 사진을 POST /avatars로 업로드하거나 앱에서 서명된 PDF를 POST /documents로 전송합니다. 이제 실제 HTTP 요청으로 동작을 검증해야 합니다. 로컬 파일을 선택하고, 폼 필드에 연결하고, 요청을 전송한 뒤 응답까지 확인해야 합니다.
파일 업로드는 JSON이 아니라 multipart/form-data를 사용하므로, 본문에 JSON을 붙여넣는 방식만으로는 테스트할 수 없습니다. 파일 필드를 처리하는 요청 빌더와 Runner 또는 CLI처럼 헤드리스 환경에서 실행할 때 파일 경로를 처리하는 방식이 필요합니다.
Apidog은 요청 작성과 테스트 실행을 모두 지원합니다. 이 글에서는 다음 작업을 단계별로 다룹니다.
- 단일 파일 업로드 요청 전송
- 파일과 JSON 메타데이터를 함께 전송
- 응답 assertion 작성
- Runner 및 CLI에서 파일 경로 문제 해결
멀티파트 형식 자체를 먼저 이해하고 싶다면 API의 파일 업로드를 참고하세요. 브라우저 환경에서 요청을 구성한다면 MDN FormData 문서도 유용합니다.
multipart/form-data란 무엇이며, 왜 파일 업로드에 필요한가요?
API 요청 본문은 여러 형식을 사용할 수 있습니다. Apidog의 Body 섹션에서는 form-data, x-www-form-urlencoded, JSON, XML, raw, binary 등을 선택할 수 있습니다.
일반적인 API 요청에는 JSON을 많이 사용하지만, 파일 업로드는 예외입니다.
form-data는 다음 헤더에 매핑됩니다.
Content-Type: multipart/form-data
이 형식은 파일과 일반 데이터를 하나의 요청으로 전송하기 위해 설계되었습니다. 요청 본문은 하나의 blob이 아니라 여러 개의 part로 나뉩니다.
예를 들면 다음과 같습니다.
-
caption: 일반 문자열 -
avatar: PNG 이미지 바이트 -
metadata: JSON 문자열
즉, 이미지 파일과 제목·카테고리 같은 메타데이터를 같은 요청에 포함할 수 있습니다.
x-www-form-urlencoded도 키-값 필드를 전송한다는 점에서는 비슷해 보입니다. 하지만 파일 바이트를 전송하는 형식은 아닙니다. 파일이 포함된 요청에는 form-data를 사용하세요.
Apidog에서는 각 form-data 필드에 타입을 지정할 수 있습니다.
| 필드 타입 | 용도 |
|---|---|
string |
제목, 설명, JSON 문자열 등 |
integer |
숫자 값 |
file |
로컬 파일 첨부 |
핵심은 파일 필드의 타입을 file로 바꾸는 것입니다. 그래야 Apidog이 해당 값을 일반 텍스트가 아니라 파일 첨부로 처리합니다.
단일 파일 업로드 전송 및 응답 확인
다음 API를 테스트한다고 가정하겠습니다.
POST /avatars
이 엔드포인트는 avatar 필드로 이미지 파일을 받고, 저장된 파일 URL을 JSON으로 반환합니다.
1. Body에서 form-data 선택
새 요청 또는 기존 엔드포인트에서 다음을 설정합니다.
POST https://api.example.com/avatars
그다음 Body 탭에서 form-data를 선택합니다.
Apidog은 멀티파트 요청에 맞게 Content-Type: multipart/form-data를 처리합니다.
2. 파일 필드 추가
다음 필드를 추가합니다.
| Key | Type | Value |
|---|---|---|
avatar |
file |
업로드할 이미지 |
처음에는 타입이 string일 수 있습니다. 타입 선택기에서 file로 변경하세요. 값 입력란이 텍스트 필드 대신 파일 선택 UI로 변경됩니다.
3. 로컬 파일 선택
avatar 행에서 업로드(Upload) 를 클릭하고 파일을 선택합니다.
예시:
jane-profile.png
Apidog은 선택한 파일의 로컬 경로를 요청 설정에 기록합니다.
4. 요청 전송
Send를 클릭합니다.
Apidog은 로컬 경로에서 파일을 읽고 멀티파트 요청 본문을 생성해 전송합니다.
여기서 중요한 점이 있습니다.
Apidog은 파일 바이트 자체를 클라우드에 저장하지 않고, 로컬 파일 경로를 저장합니다.
이 동작은 로컬 테스트에서는 자연스럽지만, Runner·CLI·팀 협업 환경에서는 파일 경로 문제로 이어질 수 있습니다.
성공 응답은 다음과 비슷할 수 있습니다.
{
"id": "usr_8842",
"avatarUrl": "https://cdn.example.com/avatars/usr_8842.png",
"sizeBytes": 48210,
"contentType": "image/png"
}
5. 응답 assertion 추가
200 OK 응답만으로는 충분하지 않습니다. 실제로 필요한 필드가 반환되는지 assertion을 추가하세요.
예를 들면 다음 조건을 확인할 수 있습니다.
status code == 200
$.avatarUrl exists
$.contentType == "image/png"
Apidog의 assertion UI에서는 다음과 같이 구성합니다.
- 상태 코드가
200인지 확인 - JSONPath
$.avatarUrl이 존재하는지 확인 -
$.contentType이"image/png"인지 확인
더 많은 assertion 연산자와 JSONPath 사용법은 API 확인 가이드를 참고하세요.
동일한 요청을 curl로 확인하면 다음과 같습니다.
curl -X POST https://api.example.com/avatars \
-F "avatar=@jane-profile.png"
-F는 멀티파트 필드를 만들고, @는 파일 내용을 읽도록 지정합니다. Apidog의 form-data 파일 필드는 UI를 통해 같은 작업을 수행합니다.
파일과 JSON 함께 전송
실제 업로드 API는 파일 하나만 받는 경우가 드뭅니다.
예를 들어 다음 엔드포인트를 생각해 보겠습니다.
POST /documents
이 API는 파일 외에도 제목, 카테고리, 태그 같은 메타데이터를 받을 수 있습니다.
단순 필드 추가
문자열이나 숫자 같은 단순 값은 파일 필드와 함께 추가하면 됩니다.
| Key | Type | Value |
|---|---|---|
title |
string |
Q3 Invoice |
category |
string |
billing |
file |
file |
q3-invoice.pdf |
모든 필드는 하나의 multipart/form-data 요청으로 전송됩니다.
구조화된 메타데이터는 JSON 문자열로 전송
배열 또는 중첩 객체가 필요하다면 metadata 필드를 string 타입으로 만들고 JSON을 값으로 입력하세요.
{
"title": "Q3 Invoice",
"category": "billing",
"tags": ["invoice", "2026", "paid"]
}
최종 요청은 다음 두 part로 구성됩니다.
| Key | Type | Value |
|---|---|---|
file |
file |
q3-invoice.pdf |
metadata |
string |
JSON 문자열 |
서버는 file part에서 파일을 읽고, metadata part에서 JSON을 파싱합니다.
이 패턴은 공용 API에서도 흔히 사용됩니다. 예를 들어 Stripe 파일 업로드 문서는 파일 part와 일반 필드를 함께 보내는 멀티파트 API 예시를 제공합니다.
Postman에서 마이그레이션 중이라면 Postman에서 파일 및 JSON 데이터 업로드 방법도 참고할 수 있습니다.
여러 파일 전송
여러 파일이 필요하면 file 타입 필드를 추가하면 됩니다.
예를 들어 원본 문서와 썸네일을 받는 API라면 다음처럼 구성합니다.
| Key | Type |
|---|---|
file |
file |
thumbnail |
file |
별도의 다중 파일 모드가 필요한 것이 아닙니다. API가 요구하는 각 파일 part에 대응하는 file 타입 필드를 추가하면 됩니다.
요청을 반복 가능한 테스트 시나리오로 만들기
한 번의 요청 전송은 현재 엔드포인트가 동작한다는 사실만 확인합니다. 회귀 테스트까지 하려면 업로드 요청을 저장된 테스트 시나리오에 포함하세요.
예를 들어 다음 흐름을 구성할 수 있습니다.
-
POST /avatars로 이미지 업로드 - 응답에서 사용자
id추출 -
GET /users/{id}호출 - 사용자 데이터에 아바타 URL이 유지되는지 assertion 수행
업로드 요청을 만든 뒤 시나리오의 한 단계로 저장합니다.
Apidog으로 테스트 시나리오 작성 방법에서는 단계 연결과 단계 간 값 전달을 다룹니다.
업로드 시나리오를 만들면 다음과 같이 확장할 수 있습니다.
- 배포마다 스테이징 환경에서 실행
- API 테스트 시나리오의 조건부 로직 적용
- 예약된 API 테스트 설정
다만 파일 업로드 시나리오는 실행 환경에 파일이 존재한다는 전제에 의존합니다.
함정: 다른 환경에서 실행되는 업로드
Apidog은 파일 자체가 아니라 파일 경로를 저장합니다.
로컬 머신에서는 선택한 파일이 해당 경로에 있으므로 문제가 없습니다. 하지만 같은 요청 또는 시나리오를 다른 머신에서 실행하면 저장된 경로가 더 이상 유효하지 않을 수 있습니다.
팀 협업 환경
예를 들어 사용자가 다음 파일을 선택했다고 가정합니다.
/Users/jane/pics/jane-profile.png
팀원은 요청과 파일 필드를 볼 수 있지만, 자신의 머신에는 해당 경로가 없습니다. 이 경로는 Jane의 로컬 디스크를 가리키기 때문입니다.
팀원은 다음 작업을 해야 합니다.
- 동일한 파일을 자신의 머신에 준비
- 파일 필드가 자신의 로컬 경로를 가리키도록 변경
- 요청 전송
Runner 및 CLI 환경
자동화 환경에서는 이 문제가 더 자주 발생합니다.
로컬에서는 통과하던 시나리오가 Runner 또는 CLI에서 실패할 수 있습니다. assertion 문제라기보다 실행 머신이 해당 파일을 찾지 못하는 경우가 많습니다.
해결 원칙은 단순합니다.
파일은 요청을 보내는 머신에 존재해야 하며, 요청의 파일 경로는 그 머신에서 유효해야 합니다.
Runner에서 파일 경로 설정
Runner는 배포 시 볼륨으로 마운트한 디렉터리의 파일을 읽습니다.
- Runner 배포 시
-v플래그로 호스트 디렉터리를 마운트합니다. - 업로드할 파일을 마운트된 호스트 디렉터리에 복사합니다.
- 시나리오에서 업로드 단계의 상세 정보를 엽니다.
- 오른쪽 상단의 일괄 편집(Batch Edit) 을 클릭합니다.
- 파일 필드 값을 Runner 내부 경로로 변경합니다.
예시:
/opt/runner/jane-profile.png
CLI에서 파일 경로 설정
CLI도 동일한 원칙을 따릅니다.
- CLI가 실행되는 머신에 파일을 준비합니다.
- 업로드 단계에서 일괄 편집(Batch Edit) 을 사용합니다.
- 파일 필드가 해당 머신의 실제 경로를 가리키도록 변경합니다.
예시:
/opt/apidog/runner/jane-profile.png
하드코딩 대신 환경 변수 사용
환경마다 경로가 다르다면 파일 경로를 변수로 관리하는 것이 더 안정적입니다.
예를 들어 시나리오의 파일 경로를 다음 변수로 설정합니다.
{{avatar_file_path}}
그다음 환경별로 다른 값을 지정합니다.
| 환경 | avatar_file_path |
|---|---|
| Local | /Users/jane/pics/jane-profile.png |
| Runner | /opt/runner/jane-profile.png |
| CI | /workspace/fixtures/jane-profile.png |
이렇게 하면 시나리오 자체는 수정하지 않고도 각 환경에서 적절한 파일을 사용할 수 있습니다.
Runner는 -v로 마운트한 디렉터리 아래의 파일만 읽을 수 있다는 점도 확인하세요. 파일이 마운트 대상 밖에 있다면 어떤 경로를 지정해도 Runner는 접근할 수 없습니다.
자세한 설정은 Apidog 파일 업로드 요청 문서를 참고하세요.
Apidog CLI로 워크플로 자동화
업로드 시나리오를 저장했다면 CI 파이프라인에서 헤드리스로 실행할 수 있습니다.
먼저 CLI를 설치하고 인증합니다.
npm install -g apidog-cli
apidog login --with-token <YOUR_ACCESS_TOKEN>
그다음 시나리오 ID와 환경 ID를 지정해 실행합니다.
apidog run --access-token $APIDOG_ACCESS_TOKEN -t <scenario_id> -e <env_id> -r cli
옵션은 다음과 같습니다.
| 옵션 | 설명 |
|---|---|
-t |
테스트 시나리오 ID |
-e |
환경 ID |
-r |
리포터 |
여러 리포터를 사용하려면 쉼표로 구분합니다.
apidog run \
--access-token $APIDOG_ACCESS_TOKEN \
-t <scenario_id> \
-e <env_id> \
-r cli,html,junit
CLI는 실행 결과를 종료 코드로 반환하므로 CI 파이프라인에서 성공 또는 실패 조건으로 사용할 수 있습니다.
설치 및 기본 설정은 Apidog CLI 설치 가이드를 참고하세요.
파일 업로드 단계가 있다면 다음 조건을 반드시 충족해야 합니다.
- CLI 실행 머신에 파일이 존재해야 함
- 시나리오의 파일 경로가 해당 파일을 가리켜야 함
- 가능하면 경로를 환경 변수로 관리해야 함
행별 입력 전달을 포함한 CI 설정은 Apidog CLI를 사용한 데이터 기반 테스트를 참고하세요.
자주 묻는 질문
동료가 내 파일 업로드 요청을 보낼 수 없는 이유는 무엇인가요?
Apidog은 파일 자체가 아니라 로컬 파일 경로를 저장합니다. 동료는 요청 설정을 볼 수 있지만, 저장된 경로는 사용자의 로컬 디스크를 가리킵니다.
동료가 요청을 실행하려면 자신의 머신에 파일을 준비하고 파일 필드를 자신의 경로로 변경해야 합니다. 예약된 테스트와 Runner 환경에도 같은 원리가 적용됩니다.
동일한 요청에서 파일과 JSON을 보내려면 어떻게 해야 하나요?
Body 유형을 form-data로 유지하세요.
- 파일 필드를 추가하고 타입을
file로 설정합니다. - JSON용 필드를 추가하고 타입을
string으로 설정합니다. - JSON을 문자열 값으로 입력합니다.
서버는 하나의 멀티파트 요청에서 파일 part와 JSON 문자열 part를 모두 받습니다.
Runner에서는 어떤 파일 경로를 사용해야 하나요?
배포 시 -v로 마운트한 Runner 볼륨 내부 경로를 사용해야 합니다.
예시:
/opt/runner/yourfile.jpg
파일을 마운트된 디렉터리에 복사한 뒤, 업로드 단계의 일괄 편집(Batch Edit) 에서 파일 필드 값을 해당 경로로 설정하세요.
CLI에서는 다음과 같은 경로를 사용할 수 있습니다.
/opt/apidog/runner/yourfile.jpg
파일 크기 또는 파일 타입 제한이 있나요?
실제 제한은 Apidog이 아니라 테스트 대상 API가 정의합니다. 서버의 파일 크기 제한, MIME 타입 제한, 확장자 제한을 확인하세요.
또한 허용되지 않는 파일 또는 너무 큰 파일을 전송했을 때 API가 올바른 오류 응답을 반환하는지 assertion으로 검증하는 것이 좋습니다.
업로드에는 form-data와 x-www-form-urlencoded 중 무엇을 사용해야 하나요?
파일을 전송한다면 form-data를 사용하세요.
form-data는 multipart/form-data에 매핑되며 파일 바이트 전송을 지원합니다. x-www-form-urlencoded는 파일 없이 짧은 스칼라 값을 보내는 간단한 폼에 적합합니다.
마무리
파일 업로드 테스트의 핵심은 두 가지입니다.
-
multipart/form-data요청을 올바르게 구성하기 - 테스트가 실행되는 모든 환경에서 파일 경로가 유효하도록 만들기
Apidog에서 파일 업로드 요청을 만들 때는 다음 순서를 따르면 됩니다.
- Body를
form-data로 설정 - 파일 필드 타입을
file로 변경 - 업로드(Upload) 로 로컬 파일 선택
- 필요하면 JSON 메타데이터를
string필드로 추가 - 요청 전송
- 상태 코드와 응답 본문 assertion 추가
Runner 또는 CLI로 시나리오를 실행할 때는 실행 머신에 파일을 준비하고, 일괄 편집(Batch Edit) 또는 환경 변수를 사용해 파일 경로를 해당 환경에 맞게 지정하세요.
직접 테스트해 보려면 Apidog을 다운로드한 뒤 업로드 라우트에 form-data 요청을 보내고 응답 assertion을 추가해 보세요.
Top comments (0)