JavaScript/Fetch Examples
This page contains comprehensive examples of using the JSONPlaceholder API with JavaScript and the modern Fetch API.
Basic Setup
Choose the appropriate base URL for your use case:
javascript
const BASE_URL = 'https://api.jsonplaceholder.dev';
// Helper function for API calls
async function apiCall(endpoint, options = {}) {
const url = `${BASE_URL}${endpoint}`;
const config = {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}
javascript
const BASE_URL = 'http://localhost:3000';
// Helper function for API calls
async function apiCall(endpoint, options = {}) {
const url = `${BASE_URL}${endpoint}`;
const config = {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}
Users Examples
Get All Users
javascript
async function getAllUsers() {
try {
const users = await fetch(`${BASE_URL}/users`);
const userData = await users.json();
console.log('All users:', userData);
return userData;
} catch (error) {
console.error('Error fetching users:', error);
}
}
Get User by ID
javascript
async function getUserById(userId) {
try {
const user = await apiCall(`/users/${userId}`);
console.log('User details:', user);
return user;
} catch (error) {
console.error(`Error fetching user ${userId}:`, error);
}
}
Create New User
javascript
async function createUser(userData) {
try {
const newUser = await apiCall('/users', {
method: 'POST',
body: JSON.stringify({
name: userData.name,
username: userData.username,
email: userData.email,
address: {
street: userData.address?.street || '123 Main St',
city: userData.address?.city || 'New York',
zipcode: userData.address?.zipcode || '10001'
},
phone: userData.phone || '1-555-123-4567',
website: userData.website || 'example.com'
})
});
console.log('Created user:', newUser);
return newUser;
} catch (error) {
console.error('Error creating user:', error);
}
}
### Update User
```javascript
async function updateUser(userId, updates) {
const updatedUser = await apiCall(`/users/${userId}`, {
method: 'PUT',
body: JSON.stringify({
id: userId,
name: updates.name,
username: updates.username,
email: updates.email,
...updates
})
});
console.log('Updated user:', updatedUser);
return updatedUser;
}
// Partial update with PATCH
async function patchUser(userId, updates) {
const patchedUser = await apiCall(`/users/${userId}`, {
method: 'PATCH',
body: JSON.stringify(updates)
});
console.log('Patched user:', patchedUser);
return patchedUser;
}
### Delete User
```javascript
async function deleteUser(userId) {
try {
await apiCall(`/users/${userId}`, {
method: 'DELETE'
});
console.log(`User ${userId} deleted successfully`);
return true;
} catch (error) {
console.error(`Error deleting user ${userId}:`, error);
return false;
}
}
// Usage createUser({ name: 'John Doe', username: 'johndoe', email: '[email protected]' });
// Update examples updateUser(1, { name: 'John Doe Updated', email: '[email protected]' }); patchUser(1, { email: '[email protected]' }); deleteUser(1);
## Posts Examples
### Get All Posts
```javascript
async function getAllPosts() {
const posts = await apiCall('/posts');
console.log(`Fetched ${posts.length} posts`);
return posts;
}
Get Posts by User
javascript
async function getPostsByUser(userId) {
const posts = await apiCall(`/posts?userId=${userId}`);
console.log(`User ${userId} has ${posts.length} posts`);
return posts;
}
Create New Post
javascript
async function createPost(postData) {
const newPost = await apiCall('/posts', {
method: 'POST',
body: JSON.stringify({
userId: postData.userId,
title: postData.title,
body: postData.body
})
});
console.log('Created post:', newPost);
return newPost;
}
// Usage
createPost({
userId: 1,
title: 'My First Post',
body: 'This is the content of my first post!'
});
Update Post
javascript
async function updatePost(postId, updates) {
const updatedPost = await apiCall(`/posts/${postId}`, {
method: 'PATCH',
body: JSON.stringify(updates)
});
console.log('Updated post:', updatedPost);
return updatedPost;
}
// Usage
updatePost(1, { title: 'Updated Title' });
Comments Examples
Get Comments for a Post
javascript
async function getPostComments(postId) {
const comments = await apiCall(`/posts/${postId}/comments`);
console.log(`Post ${postId} has ${comments.length} comments`);
return comments;
}
Add Comment to Post
javascript
async function addComment(postId, commentData) {
const comment = await apiCall('/comments', {
method: 'POST',
body: JSON.stringify({
postId: postId,
name: commentData.name,
email: commentData.email,
body: commentData.body
})
});
console.log('Added comment:', comment);
return comment;
}
// Usage
addComment(1, {
name: 'Great post!',
email: '[email protected]',
body: 'Thanks for sharing this information!'
});
Advanced Examples
Async/Await with Error Handling
javascript
class JSONPlaceholderAPI {
constructor(baseUrl = 'http://localhost:3000') {
this.baseUrl = baseUrl;
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const config = {
headers: {
'Content-Type': 'application/json',
},
...options
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error(`API Error for ${endpoint}:`, error.message);
throw error;
}
}
// Users
getUsers() {
return this.request('/users');
}
getUser(id) {
return this.request(`/users/${id}`);
}
getUserPosts(id) {
return this.request(`/users/${id}/posts`);
}
// Posts
getPosts(userId = null) {
const endpoint = userId ? `/posts?userId=${userId}` : '/posts';
return this.request(endpoint);
}
createPost(postData) {
return this.request('/posts', {
method: 'POST',
body: JSON.stringify(postData)
});
}
// Comments
getComments(postId = null) {
const endpoint = postId ? `/comments?postId=${postId}` : '/comments';
return this.request(endpoint);
}
}
// Usage
const api = new JSONPlaceholderAPI();
async function example() {
try {
const users = await api.getUsers();
const firstUser = users[0];
console.log('First user:', firstUser);
const userPosts = await api.getUserPosts(firstUser.id);
console.log(`${firstUser.name} has ${userPosts.length} posts`);
} catch (error) {
console.error('Example failed:', error);
}
}
example();
Batch Operations
javascript
async function batchCreatePosts(posts) {
const promises = posts.map(post => apiCall('/posts', {
method: 'POST',
body: JSON.stringify(post)
}));
try {
const results = await Promise.all(promises);
console.log(`Successfully created ${results.length} posts`);
return results;
} catch (error) {
console.error('Batch create failed:', error);
}
}
// Usage
const postsToCreate = [
{ userId: 1, title: 'Post 1', body: 'Content 1' },
{ userId: 1, title: 'Post 2', body: 'Content 2' },
{ userId: 2, title: 'Post 3', body: 'Content 3' }
];
batchCreatePosts(postsToCreate);
Real-time Data Fetching
javascript
class LiveDataFetcher {
constructor(apiUrl) {
this.apiUrl = apiUrl;
this.cache = new Map();
this.cacheTimeout = 30000; // 30 seconds
}
async fetchWithCache(endpoint) {
const cacheKey = endpoint;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
console.log('Returning cached data for:', endpoint);
return cached.data;
}
try {
const data = await apiCall(endpoint);
this.cache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
} catch (error) {
// Return cached data if available, even if expired
if (cached) {
console.log('Returning expired cached data due to error');
return cached.data;
}
throw error;
}
}
async getLiveUserData(userId) {
const [user, posts, albums, todos] = await Promise.all([
this.fetchWithCache(`/users/${userId}`),
this.fetchWithCache(`/users/${userId}/posts`),
this.fetchWithCache(`/users/${userId}/albums`),
this.fetchWithCache(`/users/${userId}/todos`)
]);
return {
user,
stats: {
postsCount: posts.length,
albumsCount: albums.length,
todosCount: todos.length,
completedTodos: todos.filter(t => t.completed).length
}
};
}
}
// Usage
const liveData = new LiveDataFetcher();
liveData.getLiveUserData(1).then(userData => {
console.log('Live user data:', userData);
});
Admin Operations
Reset All Data
javascript
async function resetAllData() {
try {
const result = await apiCall('/reset', {
method: 'POST'
});
console.log('Data reset successful:', result);
return result;
} catch (error) {
console.error('Reset failed:', error);
// Note: This will fail if ENABLE_UPDATES=0
throw error;
}
}
// Usage - only works when server has ENABLE_UPDATES=1
resetAllData().then(result => {
console.log('Reset completed at:', result.timestamp);
}).catch(error => {
console.log('Reset not available - server may be in read-only mode');
});
// Check if reset worked by getting fresh data
async function verifyReset() {
try {
await resetAllData();
// Verify by checking user count
const users = await apiCall('/users');
console.log(`Reset successful - ${users.length} users restored`);
return true;
} catch (error) {
console.log('Reset verification failed:', error.message);
return false;
}
}
Important: The reset endpoint only works when the server is running with ENABLE_UPDATES=1
. In read-only mode (ENABLE_UPDATES=0
), this endpoint will return an error.
Error Handling Patterns
Retry Logic
javascript
async function apiCallWithRetry(endpoint, options = {}, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await apiCall(endpoint, options);
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Failed after ${maxRetries} attempts: ${error.message}`);
}
// Wait before retry (exponential backoff)
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}
Loading States
javascript
class APIClient {
constructor() {
this.loadingStates = new Map();
}
setLoading(key, isLoading) {
this.loadingStates.set(key, isLoading);
console.log(`${key} loading:`, isLoading);
}
isLoading(key) {
return this.loadingStates.get(key) || false;
}
async callWithLoading(key, apiFunction) {
if (this.isLoading(key)) {
console.log(`${key} is already loading`);
return;
}
this.setLoading(key, true);
try {
const result = await apiFunction();
return result;
} finally {
this.setLoading(key, false);
}
}
}
// Usage
const client = new APIClient();
async function loadUserData(userId) {
return client.callWithLoading(`user-${userId}`, async () => {
const user = await apiCall(`/users/${userId}`);
return user;
});
}
Tips and Best Practices
- Always handle errors - Network requests can fail
- Use async/await - More readable than Promise chains
- Implement caching - Reduce unnecessary API calls
- Add loading states - Better user experience
- Use AbortController - Cancel requests when needed
- Validate data - Check response structure before using
javascript
// Example with AbortController
async function fetchWithTimeout(endpoint, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(`${BASE_URL}${endpoint}`, {
signal: controller.signal
});
clearTimeout(timeoutId);
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request timed out');
}
throw error;
}
}