When sending data to a server, you need to specify the HTTP method as POST (or PUT/PATCH),
set the Content-Type header to indicate the format, and serialize the data
in the request body.
For JSON APIs, you must set Content-Type: application/json and use
JSON.stringify() to convert your JavaScript object to a JSON string.
Basic POST Request
async function createUser(userData) {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
const newUser = await createUser({
name: 'Alice Smith',
email: 'alice@example.com'
});
Three essential elements:
method: 'POST' — tells the server you're sending data
Content-Type: application/json — tells the server the format of your data
body: JSON.stringify(data) — the actual data, serialized as a JSON string
With Validation Error Handling
async function createUser(userData) {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
const data = await response.json();
if (!response.ok) {
if (response.status === 422) {
throw { type: 'validation', errors: data.errors };
}
throw new Error(data.message || 'Request failed');
}
return data;
}
try {
const user = await createUser({ email: 'invalid' });
} catch (error) {
if (error.type === 'validation') {
error.errors.forEach(e => console.log(e.field, e.message));
} else {
console.error('Unexpected error:', error);
}
}
APIs often return structured error responses for validation failures. Parse the response
body even on error to extract field-specific error messages for better UX.
Reusable API Client
class ApiClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const config = {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
};
if (config.body && typeof config.body === 'object') {
config.body = JSON.stringify(config.body);
}
const response = await fetch(url, config);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}`);
}
return response.json();
}
get(endpoint) {
return this.request(endpoint);
}
post(endpoint, body) {
return this.request(endpoint, { method: 'POST', body });
}
put(endpoint, body) {
return this.request(endpoint, { method: 'PUT', body });
}
delete(endpoint) {
return this.request(endpoint, { method: 'DELETE' });
}
}
const api = new ApiClient('https://api.example.com');
const user = await api.post('/users', { name: 'Alice' });
A wrapper class encapsulates common patterns: setting headers, serializing JSON,
handling errors. This reduces boilerplate and ensures consistent behavior.
Try It Live
Request
Fill the form and click "Create User"
Response
Response will appear here
Common Mistakes
- Forgetting
Content-Type: application/json — the server may not parse your data
- Sending an object instead of
JSON.stringify(object) — results in "[object Object]"
- Not checking
response.ok — 400/500 errors won't throw automatically
← Back to HTTP Examples