🌐 API Call Methods

Complete guide to making API calls in JavaScript and React - from basic fetch to advanced patterns

JavaScript Fetch API

Basic GET Request

Simple fetch to retrieve data

fetch('https://api.example.com/users')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

GET with Headers

Fetch with custom headers

fetch('https://api.example.com/users', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_TOKEN'
  }
})
  .then(response => response.json())
  .then(data => console.log(data));

POST Request

Send data to server

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'John Doe',
    email: 'john@example.com'
  })
})
  .then(response => response.json())
  .then(data => console.log('Created:', data));

PUT Request

Update existing resource

fetch('https://api.example.com/users/123', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Jane Doe',
    email: 'jane@example.com'
  })
})
  .then(response => response.json())
  .then(data => console.log('Updated:', data));

PATCH Request

Partial update of resource

fetch('https://api.example.com/users/123', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'newemail@example.com'
  })
})
  .then(response => response.json())
  .then(data => console.log('Patched:', data));

DELETE Request

Delete a resource

fetch('https://api.example.com/users/123', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
})
  .then(response => {
    if (response.ok) {
      console.log('Deleted successfully');
    }
  });

Async/Await Pattern

Modern async/await syntax

async function fetchUsers() {
  try {
    const response = await fetch('https://api.example.com/users');
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error:', error);
  }
}

fetchUsers();

Multiple Requests (Promise.all)

Make multiple API calls in parallel

async function fetchMultiple() {
  try {
    const [users, posts, comments] = await Promise.all([
      fetch('https://api.example.com/users').then(r => r.json()),
      fetch('https://api.example.com/posts').then(r => r.json()),
      fetch('https://api.example.com/comments').then(r => r.json())
    ]);
    
    console.log({ users, posts, comments });
  } catch (error) {
    console.error('Error:', error);
  }
}

FormData Upload

Upload files using FormData

const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('name', 'Upload Name');

fetch('https://api.example.com/upload', {
  method: 'POST',
  body: formData
})
  .then(response => response.json())
  .then(data => console.log('Uploaded:', data));

Abort Controller

Cancel fetch requests

const controller = new AbortController();
const signal = controller.signal;

fetch('https://api.example.com/users', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Fetch aborted');
    }
  });

// Cancel the request
setTimeout(() => controller.abort(), 1000);

React API Patterns

useEffect with Fetch

Fetch data on component mount

import { useState, useEffect } from 'react';

function Users() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('https://api.example.com/users')
      .then(response => response.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      })
      .catch(error => {
        setError(error.message);
        setLoading(false);
      });
  }, []);

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

Custom useFetch Hook

Reusable fetch 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 {
        const response = await fetch(url);
        if (!response.ok) throw new Error('Failed to fetch');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// Usage
function App() {
  const { data, loading, error } = useFetch('/api/users');
  // ... render logic
}

POST with useState

Submit form data to API

import { useState } from 'react';

function CreateUser() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);

    try {
      const response = await fetch('/api/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, email })
      });
      
      if (!response.ok) throw new Error('Failed to create');
      
      const user = await response.json();
      console.log('Created:', user);
      
      // Reset form
      setName('');
      setEmail('');
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={name} onChange={e => setName(e.target.value)} />
      <input value={email} onChange={e => setEmail(e.target.value)} />
      <button disabled={loading}>
        {loading ? 'Creating...' : 'Create User'}
      </button>
    </form>
  );
}

Cleanup with AbortController

Prevent memory leaks when component unmounts

import { useState, useEffect } from 'react';

function Users() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    const controller = new AbortController();

    fetch('/api/users', { signal: controller.signal })
      .then(res => res.json())
      .then(data => setUsers(data))
      .catch(error => {
        if (error.name !== 'AbortError') {
          console.error('Fetch error:', error);
        }
      });

    // Cleanup: abort fetch if component unmounts
    return () => controller.abort();
  }, []);

  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}

React Query Pattern

Modern data fetching pattern (conceptual)

// Install: npm install @tanstack/react-query
import { useQuery, useMutation } from '@tanstack/react-query';

// Fetch users
function Users() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['users'],
    queryFn: () => fetch('/api/users').then(r => r.json())
  });

  if (isLoading) return 'Loading...';
  if (error) return 'Error: ' + error.message;

  return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}

// Create user with mutation
function CreateUser() {
  const mutation = useMutation({
    mutationFn: (newUser) => 
      fetch('/api/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newUser)
      }).then(r => r.json())
  });

  return (
    <button onClick={() => mutation.mutate({ name: 'John' })}>
      Create User
    </button>
  );
}

SWR Pattern

Stale-While-Revalidate strategy

// Install: npm install swr
import useSWR from 'swr';

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

function Users() {
  const { data, error, isLoading } = useSWR('/api/users', fetcher, {
    refreshInterval: 3000 // Poll every 3s
  });

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;

  return (
    <ul>
      {data.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Axios Library

Basic GET

Axios GET request

// Install: npm install axios
import axios from 'axios';

axios.get('https://api.example.com/users')
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

POST Request

Axios POST with data

import axios from 'axios';

axios.post('https://api.example.com/users', {
  name: 'John Doe',
  email: 'john@example.com'
})
  .then(response => console.log('Created:', response.data))
  .catch(error => console.error(error));

Axios Instance

Create reusable axios instance with defaults

import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

// Use the instance
api.get('/users').then(res => console.log(res.data));
api.post('/users', { name: 'Jane' });

Axios Interceptors

Add request/response interceptors

import axios from 'axios';

// Request interceptor
axios.interceptors.request.use(
  config => {
    config.headers.Authorization = 'Bearer ' + getToken();
    return config;
  },
  error => Promise.reject(error)
);

// Response interceptor
axios.interceptors.response.use(
  response => response,
  error => {
    if (error.response?.status === 401) {
      // Handle unauthorized
      redirectToLogin();
    }
    return Promise.reject(error);
  }
);

Concurrent Requests

Multiple requests with axios.all

import axios from 'axios';

Promise.all([
  axios.get('/api/users'),
  axios.get('/api/posts'),
  axios.get('/api/comments')
])
  .then(([users, posts, comments]) => {
    console.log(users.data, posts.data, comments.data);
  })
  .catch(error => console.error(error));

GraphQL

Basic GraphQL Query

Fetch data with GraphQL

const query = `
  query GetUsers {
    users {
      id
      name
      email
    }
  }
`;

fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query })
})
  .then(res => res.json())
  .then(data => console.log(data.data.users));

GraphQL Mutation

Create/update data with mutation

const mutation = `
  mutation CreateUser($name: String!, $email: String!) {
    createUser(name: $name, email: $email) {
      id
      name
      email
    }
  }
`;

const variables = {
  name: 'John Doe',
  email: 'john@example.com'
};

fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: mutation, variables })
})
  .then(res => res.json())
  .then(data => console.log(data.data.createUser));

Apollo Client (React)

GraphQL client for React

// Install: npm install @apollo/client graphql
import { ApolloClient, InMemoryCache, gql, useQuery } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://api.example.com/graphql',
  cache: new InMemoryCache()
});

const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
    }
  }
`;

function Users() {
  const { loading, error, data } = useQuery(GET_USERS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <ul>
      {data.users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

WebSocket / Real-time

WebSocket Connection

Real-time bidirectional communication

const socket = new WebSocket('wss://api.example.com/socket');

socket.addEventListener('open', (event) => {
  console.log('Connected to WebSocket');
  socket.send('Hello Server!');
});

socket.addEventListener('message', (event) => {
  console.log('Message from server:', event.data);
});

socket.addEventListener('close', (event) => {
  console.log('Disconnected from WebSocket');
});

socket.addEventListener('error', (error) => {
  console.error('WebSocket error:', error);
});

Socket.IO (React)

Real-time events with Socket.IO

// Install: npm install socket.io-client
import { useEffect, useState } from 'react';
import { io } from 'socket.io-client';

function Chat() {
  const [messages, setMessages] = useState([]);
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const newSocket = io('http://localhost:3001');
    setSocket(newSocket);

    newSocket.on('message', (message) => {
      setMessages(prev => [...prev, message]);
    });

    return () => newSocket.close();
  }, []);

  const sendMessage = (text) => {
    socket?.emit('message', text);
  };

  return (
    <div>
      {messages.map((msg, i) => <div key={i}>{msg}</div>)}
      <button onClick={() => sendMessage('Hello!')}>Send</button>
    </div>
  );
}

Server-Sent Events (SSE)

One-way server push events

const eventSource = new EventSource('https://api.example.com/events');

eventSource.addEventListener('message', (event) => {
  const data = JSON.parse(event.data);
  console.log('New message:', data);
});

eventSource.addEventListener('error', (error) => {
  console.error('SSE error:', error);
  eventSource.close();
});

// Close connection
// eventSource.close();