Intermediate
Chapter 14 · 9 min read
File Upload & Multipart Requests
Upload files via multipart/form-data, handle binary data, test file validation, and work with mixed payloads (files + JSON).
File Upload & Multipart Requests
Many APIs accept file uploads — profile pictures, documents, CSV imports. These use multipart/form-data encoding instead of JSON. Understanding how to construct and test these requests is essential.
Multipart Form Data
Unlike JSON, multipart requests can contain both files and text fields in a single request. Each part has its own content type, and boundaries separate the parts.
What to Test
- Valid file upload with correct type/size
- Invalid file types (e.g., uploading .exe when only images allowed)
- File size limits (too large, zero bytes)
- Multiple file uploads
- Mixed payload: file + metadata fields
file-upload.test.js
// File upload using FormData with Fetch
const formData = new FormData();
// Create a test file from a Blob
const fileContent = new Blob(['Hello, this is test content'], {
type: 'text/plain'
});
formData.append('file', fileContent, 'test-file.txt');
formData.append('description', 'Test file upload');
formData.append('category', 'documents');
const response = await fetch('https://httpbin.org/post', {
method: 'POST',
body: formData
// Note: Don't set Content-Type — Fetch sets it with boundary automatically
});
const result = await response.json();
console.assert(response.status === 200);
console.log('Uploaded files:', Object.keys(result.files));
console.log('Form fields:', result.form);
// Multiple files
const multiForm = new FormData();
multiForm.append('file1', new Blob(['File 1 content']), 'file1.txt');
multiForm.append('file2', new Blob(['File 2 content']), 'file2.txt');
const multiResp = await fetch('https://httpbin.org/post', {
method: 'POST',
body: multiForm
});
const multiResult = await multiResp.json();
console.assert(Object.keys(multiResult.files).length === 2);
// Binary upload (e.g., image as raw bytes)
const binaryData = new Uint8Array([137, 80, 78, 71]); // PNG header
const binaryResp = await fetch('https://httpbin.org/post', {
method: 'POST',
headers: { 'Content-Type': 'application/octet-stream' },
body: binaryData
});
console.assert(binaryResp.status === 200);
console.log('File upload tests passed!');
FileUploadTest.java
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
import org.testng.annotations.Test;
import java.io.File;
public class FileUploadTest {
@Test
public void testSingleFileUpload() {
File testFile = new File("src/test/resources/test-file.txt");
given()
.multiPart("file", testFile, "text/plain")
.formParam("description", "Test file upload")
.formParam("category", "documents")
.when()
.post("https://httpbin.org/post")
.then()
.statusCode(200)
.body("files", not(anEmptyMap()))
.body("form.description", equalTo("Test file upload"));
}
@Test
public void testMultipleFileUpload() {
given()
.multiPart("file1", new File("src/test/resources/file1.txt"))
.multiPart("file2", new File("src/test/resources/file2.txt"))
.when()
.post("https://httpbin.org/post")
.then()
.statusCode(200)
.body("files.size()", equalTo(2));
}
@Test
public void testFileUploadWithJson() {
// Mixed: file + JSON metadata
given()
.multiPart("file", new File("src/test/resources/test-file.txt"))
.multiPart("metadata", "{\"type\": \"report\"}",
"application/json")
.when()
.post("https://httpbin.org/post")
.then()
.statusCode(200);
}
@Test
public void testUploadByteArray() {
byte[] content = "Dynamic content".getBytes();
given()
.multiPart("file", "dynamic.txt", content, "text/plain")
.when()
.post("https://httpbin.org/post")
.then()
.statusCode(200);
}
}
test_file_upload.py
import requests
import io
def test_single_file_upload():
"""Upload a single file"""
files = {
'file': ('test-file.txt', b'Hello, this is test content', 'text/plain')
}
data = {
'description': 'Test file upload',
'category': 'documents'
}
response = requests.post(
'https://httpbin.org/post',
files=files,
data=data
)
assert response.status_code == 200
result = response.json()
assert 'file' in result['files']
assert result['form']['description'] == 'Test file upload'
def test_multiple_files():
"""Upload multiple files at once"""
files = [
('files', ('file1.txt', b'File 1 content', 'text/plain')),
('files', ('file2.txt', b'File 2 content', 'text/plain'))
]
response = requests.post('https://httpbin.org/post', files=files)
assert response.status_code == 200
def test_file_from_disk():
"""Upload a file from disk"""
# Create a temp file
import tempfile, os
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt',
delete=False) as f:
f.write('Content from disk')
temp_path = f.name
try:
with open(temp_path, 'rb') as f:
response = requests.post(
'https://httpbin.org/post',
files={'file': f}
)
assert response.status_code == 200
finally:
os.unlink(temp_path)
def test_binary_upload():
"""Upload raw binary data"""
binary_data = bytes([137, 80, 78, 71]) # PNG header bytes
response = requests.post(
'https://httpbin.org/post',
data=binary_data,
headers={'Content-Type': 'application/octet-stream'}
)
assert response.status_code == 200
API Testing
Intermediate
File Upload & Multipart Requests
Written by PV
© 2026 All Rights Reserved