Definition
The Content-Type header is an HTTP header that specifies the media type (MIME type) of the request or response body. It tells the recipient how to interpret the data being sent.
The header consists of:
- Type/Subtype - Media type (e.g.,
application/json,text/html) - Optional Parameters - Character encoding, boundaries (e.g.,
charset=utf-8)
Common Content-Type values:
application/json- JSON dataapplication/xml- XML datatext/html- HTML documentstext/plain- Plain textmultipart/form-data- File uploadsapplication/x-www-form-urlencoded- Form submissions
Content-Type is critical for REST APIs, as it determines how the server parses incoming requests and how clients interpret responses.
Example
JSON Request:
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 89
{
"name": "Alice Smith",
"email": "[email protected]",
"role": "developer"
}
JSON Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 142
{
"id": 123,
"name": "Alice Smith",
"email": "[email protected]",
"createdAt": "2026-01-09T10:30:00Z"
}
File Upload (multipart/form-data):
POST /api/upload HTTP/1.1
Host: api.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="document.pdf"
Content-Type: application/pdf
[Binary PDF data]
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Code Example
JavaScript (Fetch API):
// Sending JSON (automatic Content-Type setting)
const createUser = async (userData) => {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // Explicitly set
'Authorization': 'Bearer YOUR_TOKEN'
},
body: JSON.stringify(userData) // Must match Content-Type
});
// Check response Content-Type
const contentType = response.headers.get('Content-Type');
console.log('Response Content-Type:', contentType);
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else if (contentType && contentType.includes('text/plain')) {
return await response.text();
} else {
throw new Error(`Unexpected Content-Type: ${contentType}`);
}
};
// Sending Form Data (automatic Content-Type with boundary)
const uploadFile = async (file) => {
const formData = new FormData();
formData.append('file', file);
formData.append('description', 'User uploaded file');
const response = await fetch('https://api.example.com/upload', {
method: 'POST',
// DO NOT set Content-Type manually for FormData
// Browser sets it with correct boundary
body: formData
});
return await response.json();
};
// Sending URL-encoded Form Data
const submitForm = async (formData) => {
const params = new URLSearchParams(formData);
const response = await fetch('https://api.example.com/form', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params.toString()
});
return await response.json();
};
Python (requests library):
import requests
# Sending JSON
def create_user(user_data):
response = requests.post(
'https://api.example.com/users',
json=user_data, # Automatically sets Content-Type: application/json
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
# Check response Content-Type
content_type = response.headers.get('Content-Type')
print(f'Response Content-Type: {content_type}')
if content_type and 'application/json' in content_type:
return response.json()
elif content_type and 'text/plain' in content_type:
return response.text
else:
raise ValueError(f'Unexpected Content-Type: {content_type}')
# Sending File Upload
def upload_file(file_path):
with open(file_path, 'rb') as file:
files = {'file': ('document.pdf', file, 'application/pdf')}
data = {'description': 'User uploaded file'}
response = requests.post(
'https://api.example.com/upload',
files=files,
data=data
# Content-Type automatically set with boundary
)
return response.json()
# Sending URL-encoded Form Data
def submit_form(form_data):
response = requests.post(
'https://api.example.com/form',
data=form_data, # Automatically sets Content-Type: application/x-www-form-urlencoded
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
return response.json()
Diagram
graph TB
subgraph "Request Content-Types"
REQ1[application/json]
REQ2[application/xml]
REQ3[multipart/form-data]
REQ4[application/x-www-form-urlencoded]
REQ5[text/plain]
end
subgraph "Response Content-Types"
RES1[application/json]
RES2[text/html]
RES3[application/pdf]
RES4[image/png]
RES5[text/csv]
end
subgraph "Server Processing"
PARSE[Parse Body Based on Content-Type]
VALIDATE[Validate Format]
PROCESS[Process Data]
end
REQ1 --> PARSE
REQ2 --> PARSE
REQ3 --> PARSE
REQ4 --> PARSE
REQ5 --> PARSE
PARSE --> VALIDATE
VALIDATE --> PROCESS
PROCESS --> RES1
PROCESS --> RES2
PROCESS --> RES3
PROCESS --> RES4
PROCESS --> RES5
Analogy
Think of Content-Type like a label on food packaging:
- Content-Type: application/json β “This is JSON, parse it as structured data”
- Content-Type: text/plain β “This is plain text, no special parsing needed”
- Content-Type: multipart/form-data β “This contains multiple parts (files + fields)”
Without the label, you wouldn’t know if it’s soup, cereal, or frozen pizza. Without Content-Type, the server doesn’t know how to interpret the data.
Best Practices
- Always Set Content-Type - Specify the body format in requests and responses
- Match Body Format - Ensure the actual content matches the declared Content-Type
- Include Charset - Add
charset=utf-8for text-based formats - Validate on Server - Check Content-Type before parsing the body
- Use Standard MIME Types - Follow IANA registered media types
- Don’t Override FormData - Let the browser set Content-Type with boundary for multipart uploads
- Set Correct Type for Downloads - Use
application/octet-streamor specific types for file downloads
Common Mistakes
- Missing Content-Type - Sending JSON without
Content-Type: application/json - Wrong Content-Type - Declaring
application/jsonbut sending XML or plain text - Hardcoded Boundary - Manually setting boundary in
multipart/form-datainstead of letting the client generate it - No Charset - Not specifying
charset=utf-8for text/JSON responses - Ignoring Content-Type - Parsing request body without checking Content-Type first
- Using application/json for HTML - Returning HTML with
Content-Type: application/json - Trusting Client Header - Not validating Content-Type matches actual content