Practice and reinforce the concepts from Lesson 4
By the end of this activity, you will:
Access the template here: POST Request Handler Template
git clone
and navigate to the template folderindex.html
in your browser to start!The template includes:
We'll primarily use JSONPlaceholder for reliable testing, but you can enhance with fun themes:
POST /posts
- Create blog postsPOST /comments
- Add commentsPOST /users
- Register usersCreate a function that sends data to the JSONPlaceholder API.
async function createPost() {
const postData = {
title: 'My First API Post',
body: 'Learning to send data with POST requests is awesome!',
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(postData)
});
const result = await response.json();
console.log('Created post:', result);
document.getElementById('result').innerHTML = `
<h3>Post Created Successfully!</h3>
<p><strong>ID:</strong> ${result.id}</p>
<p><strong>Title:</strong> ${result.title}</p>
<p><strong>Body:</strong> ${result.body}</p>
`;
} catch (error) {
console.error('Error creating post:', error);
}
}
async function createPokemonTeam() {
const teamData = {
title: 'My Epic Pokemon Team',
body: JSON.stringify({
pokemon: ['Pikachu', 'Charmander', 'Squirtle'],
strategy: 'Balanced offense and defense',
region: 'Kanto'
}),
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(teamData)
});
const result = await response.json();
const teamInfo = JSON.parse(result.body);
document.getElementById('result').innerHTML = `
<h3>Pokemon Team Created!</h3>
<p><strong>Team:</strong> ${teamInfo.pokemon.join(', ')}</p>
<p><strong>Strategy:</strong> ${teamInfo.strategy}</p>
<p><strong>Region:</strong> ${teamInfo.region}</p>
<p><strong>Team ID:</strong> ${result.id}</p>
`;
} catch (error) {
console.error('Error creating team:', error);
}
}
async function createRecipe() {
const recipeData = {
title: 'Perfect Chocolate Chip Cookies',
body: JSON.stringify({
ingredients: ['flour', 'butter', 'chocolate chips', 'sugar'],
cookTime: '12 minutes',
difficulty: 'Easy',
servings: 24
}),
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(recipeData)
});
const result = await response.json();
const recipe = JSON.parse(result.body);
document.getElementById('result').innerHTML = `
<h3>Recipe Added!</h3>
<p><strong>Recipe:</strong> ${result.title}</p>
<p><strong>Cook Time:</strong> ${recipe.cookTime}</p>
<p><strong>Difficulty:</strong> ${recipe.difficulty}</p>
<p><strong>Serves:</strong> ${recipe.servings}</p>
`;
} catch (error) {
console.error('Error creating recipe:', error);
}
}
Create an interactive form that converts user input into POST requests.
<form id="userForm">
<input type="text" id="name" placeholder="Full Name" required>
<input type="email" id="email" placeholder="Email" required>
<input type="text" id="website" placeholder="Website">
<button type="submit">Create User</button>
</form>
document.getElementById('userForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
website: document.getElementById('website').value || 'Not provided'
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData)
});
const result = await response.json();
document.getElementById('result').innerHTML = `
<h3>User Created Successfully!</h3>
<p><strong>ID:</strong> ${result.id}</p>
<p><strong>Name:</strong> ${result.name}</p>
<p><strong>Email:</strong> ${result.email}</p>
`;
// Clear form
document.getElementById('userForm').reset();
} catch (error) {
document.getElementById('result').innerHTML = '<p style="color: red;">Error creating user</p>';
}
});
<form id="pokemonForm">
<input type="text" id="teamName" placeholder="Team Name" required>
<input type="text" id="pokemon1" placeholder="Pokemon 1" required>
<input type="text" id="pokemon2" placeholder="Pokemon 2" required>
<input type="text" id="pokemon3" placeholder="Pokemon 3" required>
<select id="strategy">
<option value="offensive">Offensive</option>
<option value="defensive">Defensive</option>
<option value="balanced">Balanced</option>
</select>
<button type="submit">Create Team</button>
</form>
document.getElementById('pokemonForm').addEventListener('submit', async (e) => {
e.preventDefault();
const teamData = {
title: document.getElementById('teamName').value,
body: JSON.stringify({
pokemon: [
document.getElementById('pokemon1').value,
document.getElementById('pokemon2').value,
document.getElementById('pokemon3').value
],
strategy: document.getElementById('strategy').value,
createdAt: new Date().toISOString()
}),
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(teamData)
});
const result = await response.json();
const team = JSON.parse(result.body);
document.getElementById('result').innerHTML = `
<h3>Pokemon Team Created!</h3>
<p><strong>Team:</strong> ${result.title}</p>
<p><strong>Pokemon:</strong> ${team.pokemon.join(', ')}</p>
<p><strong>Strategy:</strong> ${team.strategy}</p>
<p><strong>Team ID:</strong> ${result.id}</p>
`;
document.getElementById('pokemonForm').reset();
} catch (error) {
document.getElementById('result').innerHTML = '<p style="color: red;">Error creating team</p>';
}
});
<form id="recipeForm">
<input type="text" id="recipeName" placeholder="Recipe Name" required>
<textarea id="ingredients" placeholder="Ingredients (one per line)" required></textarea>
<input type="number" id="cookTime" placeholder="Cook Time (minutes)" required>
<select id="difficulty">
<option value="Easy">Easy</option>
<option value="Medium">Medium</option>
<option value="Hard">Hard</option>
</select>
<button type="submit">Add Recipe</button>
</form>
document.getElementById('recipeForm').addEventListener('submit', async (e) => {
e.preventDefault();
const recipeData = {
title: document.getElementById('recipeName').value,
body: JSON.stringify({
ingredients: document.getElementById('ingredients').value.split('\n').filter(i => i.trim()),
cookTime: `${document.getElementById('cookTime').value} minutes`,
difficulty: document.getElementById('difficulty').value,
addedAt: new Date().toISOString()
}),
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(recipeData)
});
const result = await response.json();
const recipe = JSON.parse(result.body);
document.getElementById('result').innerHTML = `
<h3>Recipe Added!</h3>
<p><strong>Recipe:</strong> ${result.title}</p>
<p><strong>Ingredients:</strong> ${recipe.ingredients.length} items</p>
<p><strong>Cook Time:</strong> ${recipe.cookTime}</p>
<p><strong>Difficulty:</strong> ${recipe.difficulty}</p>
`;
document.getElementById('recipeForm').reset();
} catch (error) {
document.getElementById('result').innerHTML = '<p style="color: red;">Error adding recipe</p>';
}
});
Create a robust POST function with comprehensive error handling.
Starter Template:
async function createComment(postId, commentData) {
try {
// TODO: Implement POST request with error handling
} catch (error) {
// TODO: Handle different types of errors
}
}
Your Mission:
/posts/${postId}/comments
Test Scenarios:
Create a function that sends multiple POST requests and handles all responses.
Challenge: Create a "bulk create" function that:
Bonus Points:
Challenge: "Failed to fetch" error Solution: Check URL spelling and network connection
Challenge: 400 Bad Request response Solution: Verify JSON structure and required fields
Challenge: CORS errors in browser Solution: JSONPlaceholder handles CORS - check URL format
Challenge: Response not showing expected data Solution: JSONPlaceholder simulates creation but doesn't persist data
class FormWizard {
constructor() {
this.steps = [];
this.currentStep = 0;
}
addStep(data) {
this.steps.push(data);
}
async submitAll() {
const combinedData = {
title: 'Multi-Step Submission',
body: JSON.stringify({
steps: this.steps,
completedAt: new Date().toISOString()
}),
userId: 1
};
// Submit to JSONPlaceholder
return await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(combinedData)
});
}
}
async function submitBatch(items) {
const batchData = {
title: 'Batch Submission',
body: JSON.stringify({
items: items,
count: items.length,
submittedAt: new Date().toISOString()
}),
userId: 1
};
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(batchData)
});
return await response.json();
} catch (error) {
console.error('Batch submission failed:', error);
}
}
// Example: Submit multiple Pokemon
const pokemonBatch = [
{ name: 'Pikachu', type: 'Electric' },
{ name: 'Charmander', type: 'Fire' },
{ name: 'Squirtle', type: 'Water' }
];
submitBatch(pokemonBatch);
class FormSync {
constructor(formId) {
this.form = document.getElementById(formId);
this.draftKey = `draft_${formId}`;
this.setupAutosave();
this.loadDraft();
}
setupAutosave() {
this.form.addEventListener('input', () => {
this.saveDraft();
});
}
saveDraft() {
const formData = new FormData(this.form);
const data = Object.fromEntries(formData);
localStorage.setItem(this.draftKey, JSON.stringify(data));
}
async submitFinal() {
const formData = new FormData(this.form);
const data = Object.fromEntries(formData);
// Submit to API
const result = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: 'Auto-saved Form',
body: JSON.stringify(data),
userId: 1
})
});
// Clear draft after successful submission
localStorage.removeItem(this.draftKey);
return result;
}
}
In the next concept, we'll explore PUT and DELETE requests to complete the full CRUD operations suite. Understanding POST requests is crucial for creating interactive web applications that can save user data.
💡 Tip: POST requests are the foundation of most interactive web features. Master these patterns and you'll be ready to build full-featured applications!