Custom Media Types
Generate valid payloads for media types that Schemathesis doesn't recognize by default.
When to use custom media types
Use custom media type strategies when your API accepts content that Schemathesis can't generate automatically:
- Binary formats - PDFs, images, audio files, or proprietary formats
- Specialized text formats - Custom configuration files, or domain-specific formats
Quick Start: PDF File Upload
Problem: Your API accepts PDF uploads, but Schemathesis generates invalid binary data that fails validation.
Register a strategy that generates valid PDF headers:
# pdf_strategy.py
from hypothesis import strategies as st
import schemathesis
pdf_strategy = st.sampled_from(
[
b"%PDF-1.4\n1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\nxref\n0 3\n0000000000 65535 f \ntrailer\n<<\n/Size 3\n/Root 10 R\n>>\nstartxref\n9\n%%EOF",
b"%PDF-1.5\n%\xe2\xe3\xcf\xd3\n1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\nxref\n0 3\n0000000000 65535 f \ntrailer\n<<\n/Size 3\n/Root 1 0 R\n>>\nstartxref\n9\n%%EOF",
]
)
# Register the strategy for PDF media type
schemathesis.openapi.media_type("application/pdf", pdf_strategy)
Result: File upload endpoints receive valid PDF content instead of random bytes.
Media Type Matching
The media type string you register must exactly match the one defined in your OpenAPI specification. For example, if your spec uses application/pdf
, register exactly application/pdf
- not application/x-pdf
or any other variation. Check your OpenAPI schema's requestBody.content
section to find the exact media type strings.
Common Media Type Patterns
Image files
image_strategy = st.sampled_from(
[
# Minimal PNG
b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\tpHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\nIDAT\x08\x1dc\xf8\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00IEND\xaeB`\x82",
# Minimal JPEG
b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c $.' \",#\x1c\x1c(7),01444\x1f'9=82<.342\xff\xc0\x00\x11\x08\x00\x01\x00\x01\x01\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x14\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x00?\x00\xff\xd9",
]
)
schemathesis.openapi.media_type("image/*", image_strategy)
Archives
import zipfile
import io
def create_test_zip():
"""Create a minimal valid ZIP file"""
buffer = io.BytesIO()
with zipfile.ZipFile(buffer, 'w') as zf:
zf.writestr("test.txt", "test content")
return buffer.getvalue()
zip_strategy = st.just(create_test_zip())
schemathesis.openapi.media_type("application/zip", zip_strategy)
Media Type Aliases
# Register PDF strategy with common aliases
schemathesis.openapi.media_type(
"application/pdf",
pdf_strategy,
aliases=["application/x-pdf", "application/acrobat"]
)
# Handles application/pdf, application/x-pdf, and application/acrobat
Dynamic Content Generation
from hypothesis import strategies as st
@st.composite
def dynamic_xml(draw):
"""Generate XML with random but valid structure"""
tag_name = draw(st.text(
alphabet=st.characters(
whitelist_categories=["L"]), min_size=3, max_size=10
)
)
content = draw(st.text(min_size=1, max_size=50))
return f"<?xml version='1.0'?><{tag_name}>{content}</{tag_name}>".encode()
schemathesis.openapi.media_type("application/xml", dynamic_xml())