API Integration Examples

Complete examples of HTTP Client usage, Loading States, and Error Handling with Now.js

Example 1: User List with Loading States

ตัวอย่างการดึงข้อมูล users จาก API พร้อม skeleton loading และ error handling

JavaScript Code:

// Load users from API
              async function loadUsers() {
              const container = document.getElementById('userListContainer');

              // Show loading skeleton
              container.innerHTML = createSkeletonCards(6);

              try {
              const response = await fetch('https://jsonplaceholder.typicode.com/users');

              if (!response.ok) {
              throw new Error(`HTTP error! status: ${response.status}`);
              }

              const users = await response.json();

              // Render user cards
              container.innerHTML = users.map(user => `
              <div class="card">
              <div class="card-header">
              <h3>${user.name}</h3>
              </div>
              <div class="card-body">
              <p><strong>Email:</strong> ${user.email}</p>
              <p><strong>Phone:</strong> ${user.phone}</p>
              <p><strong>Company:</strong> ${user.company.name}</p>
              </div>
              </div>
              `).join('');

              } catch (error) {
              // Show error state
              container.innerHTML = `
              <div class="error-state">
              <div class="icon-alert-circle"></div>
              <h3>Failed to load users</h3>
              <p>${error.message}</p>
              <button onclick="loadUsers()" class="button primary">Retry</button>
              </div>
              `;
              }
              }

Example 2: Weather Widget with Auto-Refresh

Real-time weather data พร้อม loading spinner และ auto-refresh ทุก 30 วินาที

Loading weather data...

JavaScript Code:

// Weather widget with auto-refresh
              let autoRefreshInterval = null;

              async function loadWeather() {
              const widget = document.getElementById('weatherWidget');

              // Show loading spinner
              widget.innerHTML = `
              <div class="weather-loading">
              <div class="spinner"></div>
              <p>Loading weather data...</p>
              </div>
              `;

              try {
              // Using OpenWeatherMap API (requires API key)
              const lat = 13.7563; // Bangkok
              const lon = 100.5018;
              const apiKey = 'demo'; // Replace with your API key

              const response = await fetch(
              `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}&units=metric`
              );

              if (!response.ok) throw new Error('Weather API failed');

              const data = await response.json();

              // Render weather data
              widget.innerHTML = `
              <div class="weather-content">
              <h3>${data.name}</h3>
              <div class="weather-temp">${Math.round(data.main.temp)}°C</div>
              <p>${data.weather[0].description}</p>
              <div class="weather-details">
              <span>Humidity: ${data.main.humidity}%</span>
              <span>Wind: ${data.wind.speed} m/s</span>
              </div>
              <small>Last updated: ${new Date().toLocaleTimeString()}</small>
              </div>
              `;

              } catch (error) {
              widget.innerHTML = `
              <div class="error-state">
              <p>Failed to load weather data</p>
              <button onclick="loadWeather()" class="button">Retry</button>
              </div>
              `;
              }
              }

              // Toggle auto-refresh
              function toggleAutoRefresh() {
              if (autoRefreshInterval) {
              clearInterval(autoRefreshInterval);
              autoRefreshInterval = null;
              } else {
              autoRefreshInterval = setInterval(loadWeather, 30000);
              }
              }

Example 3: Product Search with Debounce

Search products พร้อม debounce และ loading indicator

Type to search products...

JavaScript Code:

// Debounce function
              function debounce(func, wait) {
              let timeout;
              return function executedFunction(...args) {
              const later = () => {
              clearTimeout(timeout);
              func(...args);
              };
              clearTimeout(timeout);
              timeout = setTimeout(later, wait);
              };
              }

              // Search products
              async function searchProducts(query) {
              const resultsContainer = document.getElementById('productResults');
              const loadingIndicator = document.getElementById('searchLoading');

              if (!query.trim()) {
              resultsContainer.innerHTML = '<p class="text-muted">Type to search products...</p>';
              return;
              }

              // Show loading
              loadingIndicator.style.display = 'block';

              try {
              const response = await fetch(
              `https://dummyjson.com/products/search?q=${encodeURIComponent(query)}`
              );

              const data = await response.json();

              // Hide loading
              loadingIndicator.style.display = 'none';

              if (data.products.length === 0) {
              resultsContainer.innerHTML = '<p>No products found</p>';
              return;
              }

              // Render results
              resultsContainer.innerHTML = data.products.map(product => `
              <div class="product-card">
              <img src="${product.thumbnail}" alt="${product.title}">
              <h4>${product.title}</h4>
              <p class="price">$${product.price}</p>
              <p class="rating">⭐ ${product.rating}</p>
              </div>
              `).join('');

              } catch (error) {
              loadingIndicator.style.display = 'none';
              resultsContainer.innerHTML = `<p class="error">Search failed: ${error.message}</p>`;
              }
              }
              // Attach debounced search to input
              const debouncedSearch = debounce(searchProducts, 500);
              document.getElementById('productSearch').addEventListener('input', (e) => {
              debouncedSearch(e.target.value);
              });

Example 4: Form Submission (POST/PUT/DELETE)

ตัวอย่างการส่งข้อมูลไปยัง API พร้อม loading state และ success/error feedback


                  <div class="form-container">
                  <form id="userForm" class="form">
                  <div>
                  <label for="userName">Name:</label>
                  <span class="form-control">
                  <input type="text" id="userName" class="input" required>
                  </span>
                  </div>
                  <div>
                  <label for="userEmail">Email:</label>
                  <span class="form-control">
                  <input type="email" id="userEmail" class="input" required>
                  </span>
                  </div>
                  <div>
                  <label for="userJob">Job:</label>
                  <span class="form-control">
                  <input type="text" id="userJob" class="input" required>
                  </span>
                  </div>
                  <div class="form-actions">
                  <button type="submit" id="submitBtn" class="button primary">
                  <span class="btn-text">Create User</span>
                  <span class="btn-loading" style="display: none;">
                  <div class="spinner-small"></div> Creating...
                  </span>
                  </button>
                  <button type="button" id="updateBtn" class="button">Update User</button>
                  <button type="button" id="deleteBtn" class="button danger">Delete User</button>
                  </div>
                  </form>

                  <div id="formFeedback" class="feedback-container"></div>
                  </div>
                

                  // Create user (POST)
                  async function createUser(userData) {
                  const submitBtn = document.getElementById('submitBtn');
                  const btnText = submitBtn.querySelector('.btn-text');
                  const btnLoading = submitBtn.querySelector('.btn-loading');

                  // Show loading state
                  btnText.style.display = 'none';
                  btnLoading.style.display = 'inline-flex';
                  submitBtn.disabled = true;

                  try {
                  const response = await fetch('https://reqres.in/api/users', {
                  method: 'POST',
                  headers: {
                  'Content-Type': 'application/json',
                  },
                  body: JSON.stringify(userData)
                  });

                  if (!response.ok) throw new Error('Failed to create user');

                  const result = await response.json();
                  showFeedback('success', `User created successfully! ID: ${result.id}`);
                  document.getElementById('userForm').reset();

                  } catch (error) {
                  showFeedback('error', `Error: ${error.message}`);
                  } finally {
                  btnText.style.display = 'inline';
                  btnLoading.style.display = 'none';
                  submitBtn.disabled = false;
                  }
                  }
                

                  // Update user (PUT)
                  async function updateUser(userId, userData) {
                  const updateBtn = document.getElementById('updateBtn');
                  updateBtn.disabled = true;
                  updateBtn.innerHTML = '<div class="spinner-small"></div> Updating...';

                  try {
                  const response = await fetch(`https://reqres.in/api/users/${userId}`, {
                  method: 'PUT',
                  headers: {
                  'Content-Type': 'application/json',
                  },
                  body: JSON.stringify(userData)
                  });

                  if (!response.ok) throw new Error('Failed to update user');

                  const result = await response.json();
                  showFeedback('success', 'User updated successfully!');

                  } catch (error) {
                  showFeedback('error', `Error: ${error.message}`);
                  } finally {
                  updateBtn.disabled = false;
                  updateBtn.textContent = 'Update User';
                  }
                  }
                

                  // Delete user (DELETE)
                  async function deleteUser(userId) {
                  if (!confirm('Are you sure you want to delete this user?')) return;

                  const deleteBtn = document.getElementById('deleteBtn');
                  deleteBtn.disabled = true;
                  deleteBtn.innerHTML = '<div class="spinner-small"></div> Deleting...';

                  try {
                  const response = await fetch(`https://reqres.in/api/users/${userId}`, {
                  method: 'DELETE'
                  });

                  if (!response.ok) throw new Error('Failed to delete user');

                  showFeedback('success', 'User deleted successfully!');
                  document.getElementById('userForm').reset();

                  } catch (error) {
                  showFeedback('error', `Error: ${error.message}`);
                  } finally {
                  deleteBtn.disabled = false;
                  deleteBtn.textContent = 'Delete User';
                  }
                  }
                

Example 5: Multiple API Calls (Concurrent)

เรียก API หลายตัวพร้อมกัน และแสดง loading state แยกกันสำหรับแต่ละ section

Statistics

Recent Posts

Tasks

JavaScript Code:

// Load multiple APIs concurrently
                async function loadDashboard() {
                try {
                // Show loading state for all cards
                showLoadingState();

                // Fetch all data concurrently
                const [users, posts, todos] = await Promise.all([
                fetch('https://jsonplaceholder.typicode.com/users').then(r => r.json()),
                fetch('https://jsonplaceholder.typicode.com/posts?_limit=5').then(r => r.json()),
                fetch('https://jsonplaceholder.typicode.com/todos?_limit=5').then(r => r.json())
                ]);

                // Render statistics
                document.getElementById('statsCard').innerHTML = `
                <h3>Statistics</h3>
                <div class="stats">
                <div class="stat-item">
                <span class="stat-value">${users.length}</span>
                <span class="stat-label">Total Users</span>
                </div>
                <div class="stat-item">
                <span class="stat-value">${posts.length}</span>
                <span class="stat-label">Recent Posts</span>
                </div>
                </div>
                `;

                // Render posts
                document.getElementById('postsCard').innerHTML = `
                <h3>Recent Posts</h3>
                <ul class="post-list">
                ${posts.map(post => `
                <li><strong>${post.title}</strong></li>
                `).join('')}
                </ul>
                `;

                // Render todos
                document.getElementById('todosCard').innerHTML = `
                <h3>Tasks</h3>
                <ul class="todo-list">
                ${todos.map(todo => `
                <li class="${todo.completed ? 'completed' : ''}">
                ${todo.title}
                </li>
                `).join('')}
                </ul>
                `;

                } catch (error) {
                console.error('Dashboard load failed:', error);
                showErrorState();
                }
                }

Example 6: Advanced Error Handling with Retry

Error handling พร้อม retry mechanism และ exponential backoff

JavaScript Code:


async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  let lastError;

  for (let i = 0; i < maxRetries; i++) {
    try {
      logMessage(`Attempt ${i + 1}/${maxRetries}...`);
      const response = await fetch(url, options);
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
      logMessage('✓ Success!', 'success');
      return await response.json();
    } catch (error) {
      lastError = error;
      logMessage(`✗ Failed: ${error.message}`, 'error');
      if (i < maxRetries - 1) {
        const delay = Math.pow(2, i) * 1000;
        logMessage(`Waiting ${delay}ms before retry...`, 'info');
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  throw new Error(`Failed after ${maxRetries} attempts: ${lastError.message}`);
}

async function testRetry() {
  const logContainer = document.getElementById('retryLog');
  logContainer.innerHTML = '<h4>Retry Log:</h4>';

  try {
    const data = await fetchWithRetry('https://httpstat.us/500', {}, 3);
  } catch (error) {
    logMessage(`Final error: ${error.message}`, 'error');
  }
}

function logMessage(message, type = 'info') {
  const logContainer = document.getElementById('retryLog');
  const entry = document.createElement('div');
  entry.className = `log-entry log-${type}`;
  entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
  logContainer.appendChild(entry);
}
            

HTTP Client Best Practices

แนวทางที่ดีในการใช้งาน HTTP Client

1. Always Handle Errors

try {
                  const response = await fetch(url);
                  if (!response.ok) throw new Error(`HTTP ${response.status}`);
                  const data = await response.json();
                  } catch (error) {
                  console.error('Request failed:', error);
                  // Show user-friendly error message
                  }

2. Use Loading States

// Show loading before request
                  setLoading(true);

                  try {
                  const data = await fetchData();
                  renderData(data);
                  } finally {
                  // Always hide loading, even if error occurs
                  setLoading(false);
                  }

3. Set Timeouts

const controller = new AbortController();
                  const timeoutId = setTimeout(() => controller.abort(), 5000);

                  try {
                  const response = await fetch(url, {
                  signal: controller.signal
                  });
                  clearTimeout(timeoutId);
                  } catch (error) {
                  if (error.name === 'AbortError') {
                  console.log('Request timeout');
                  }
                  }

4. Cache Responses

const cache = new Map();

                  async function fetchWithCache(url, ttl = 60000) {
                  const cached = cache.get(url);

                  if (cached && Date.now() - cached.timestamp < ttl) { return cached.data; } const data=await fetch(url).then(r=> r.json());
                    cache.set(url, { data, timestamp: Date.now() });

                    return data;
                    }