Skip to content

Latest commit

 

History

History
414 lines (338 loc) · 9.57 KB

File metadata and controls

414 lines (338 loc) · 9.57 KB

API & Data Fetching 🌐

Tools for making HTTP requests and managing API interactions in modern web applications.

Axios

Description: Promise-based HTTP client for the browser and node.js with request/response interceptors and automatic JSON data transformation.

Key Features:

  • Promise-based API
  • Request/response interceptors
  • Automatic JSON transformation
  • Request/response transformation
  • Error handling
  • Request cancellation
  • Wide browser support

Installation:

npm install axios

Basic Usage:

import axios from 'axios';

// Basic GET request
const fetchUsers = async () => {
  try {
    const response = await axios.get('https://jsonplaceholder.typicode.com/users');
    return response.data;
  } catch (error) {
    console.error('Error fetching users:', error);
  }
};

// POST request with data
const createUser = async (userData) => {
  try {
    const response = await axios.post('https://jsonplaceholder.typicode.com/users', userData);
    return response.data;
  } catch (error) {
    console.error('Error creating user:', error);
  }
};

// With interceptors
const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000
});

// Request interceptor
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// Response interceptor
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      // Handle unauthorized access
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

Use Cases: RESTful API calls, file uploads, request/response transformation

SWR

Description: Data fetching library with cache, revalidation, focus tracking, and more for React applications.

Key Features:

  • Automatic caching
  • Background revalidation
  • Focus revalidation
  • Error retry
  • Pagination support
  • TypeScript support
  • Small bundle size

Installation:

npm install swr

Basic Usage:

import useSWR from 'swr';

const fetcher = (url) => fetch(url).then((res) => res.json());

function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher);

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;
  
  return (
    <div>
      <h1>Hello {data.name}!</h1>
      <p>Email: {data.email}</p>
    </div>
  );
}

// With conditional fetching
function User({ userId }) {
  const { data, error } = useSWR(
    userId ? `/api/users/${userId}` : null,
    fetcher
  );

  if (error) return <div>Failed to load user</div>;
  if (!data) return <div>Loading...</div>;
  
  return <div>Hello {data.name}!</div>;
}

// With mutations
import useSWRMutation from 'swr/mutation';

async function updateUser(url, { arg }) {
  return fetch(url, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(arg),
  }).then(res => res.json());
}

function UserForm({ userId }) {
  const { trigger } = useSWRMutation(`/api/users/${userId}`, updateUser);

  const handleSubmit = async (formData) => {
    try {
      await trigger(formData);
      // Handle success
    } catch (error) {
      // Handle error
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
    </form>
  );
}

Use Cases: Real-time data, caching, background updates, React applications

SWR (Already exists - updating comparison table)

Description: Data fetching library with cache, revalidation, focus tracking, and more for React applications.

Key Features:

  • Automatic caching
  • Background revalidation
  • Focus revalidation
  • Error retry
  • Pagination support
  • TypeScript support
  • Small bundle size

Installation:

npm install swr

Basic Usage:

import useSWR from 'swr';

const fetcher = (url) => fetch(url).then((res) => res.json());

function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher);

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;
  
  return (
    <div>
      <h1>Hello {data.name}!</h1>
      <p>Email: {data.email}</p>
    </div>
  );
}

// With conditional fetching
function User({ userId }) {
  const { data, error } = useSWR(
    userId ? `/api/users/${userId}` : null,
    fetcher
  );

  if (error) return <div>Failed to load user</div>;
  if (!data) return <div>Loading...</div>;
  
  return <div>Hello {data.name}!</div>;
}

// With mutations
import useSWRMutation from 'swr/mutation';

async function updateUser(url, { arg }) {
  return fetch(url, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(arg),
  }).then(res => res.json());
}

function UserForm({ userId }) {
  const { trigger } = useSWRMutation(`/api/users/${userId}`, updateUser);

  const handleSubmit = async (formData) => {
    try {
      await trigger(formData);
      // Handle success
    } catch (error) {
      // Handle error
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
    </form>
  );
}

Use Cases: Real-time data, caching, background updates, React applications

Fetch API

Description: Modern web API for making HTTP requests, built into modern browsers and Node.js.

Key Features:

  • Native browser API
  • Promise-based
  • Stream support
  • Request/Response objects
  • No external dependencies
  • Wide browser support

Basic Usage:

// Basic GET request
const fetchUsers = async () => {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error:', error);
  }
};

// POST request with headers
const createUser = async (userData) => {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(userData),
    });

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

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error:', error);
  }
};

// With custom hook
import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// Usage
function UsersList() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <ul>
      {data?.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Use Cases: Simple HTTP requests, when you want to avoid external dependencies

Comparison Table

Library Bundle Size Caching TypeScript Learning Curve
Axios Medium Manual Good Low
SWR Small Automatic Excellent Low
Fetch API None Manual Good Low

When to Use Each

  • Axios: When you need interceptors, automatic JSON transformation, or request/response transformation
  • SWR: When you need automatic caching, background updates, and React integration
  • Fetch API: When you want to avoid external dependencies and need simple HTTP requests

Best Practices

  1. Error Handling: Always implement proper error handling for network requests
  2. Loading States: Show loading indicators during API calls
  3. Caching: Implement appropriate caching strategies for your data
  4. Request Cancellation: Cancel requests when components unmount
  5. TypeScript: Use TypeScript for better type safety with API responses
  6. Retry Logic: Implement retry mechanisms for failed requests
  7. Rate Limiting: Respect API rate limits and implement backoff strategies
  8. Security: Validate and sanitize data from APIs
  9. Testing: Mock API calls in your tests
  10. Performance: Use request deduplication and proper caching

Advanced Patterns

Request Deduplication

// Prevent duplicate requests for the same data
const requestCache = new Map();

const deduplicatedFetch = async (url) => {
  if (requestCache.has(url)) {
    return requestCache.get(url);
  }
  
  const promise = fetch(url).then(res => res.json());
  requestCache.set(url, promise);
  
  return promise;
};

Retry with Exponential Backoff

const fetchWithRetry = async (url, options = {}, retries = 3) => {
  try {
    const response = await fetch(url, options);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return response;
  } catch (error) {
    if (retries > 0) {
      await new Promise(resolve => setTimeout(resolve, 1000 * (4 - retries)));
      return fetchWithRetry(url, options, retries - 1);
    }
    throw error;
  }
};