Network Communication APIs

1. Fetch API and Request/Response Objects

Method/Property Syntax Description Browser Support
fetch fetch(url, options) Makes HTTP request, returns Promise<Response>. Modern replacement for XMLHttpRequest. Modern Browsers
Request Constructor new Request(url, options) Creates Request object that can be reused. Options include method, headers, body, mode, credentials. Modern Browsers
Response Constructor new Response(body, options) Creates Response object. Options include status, statusText, headers. Used in Service Workers. Modern Browsers
Headers Constructor new Headers(init) Creates Headers object for request/response headers. Methods: get, set, append, delete, has. Modern Browsers
Fetch Option Type Description Default
method string HTTP method: GET, POST, PUT, DELETE, PATCH, etc. "GET"
headers Headers | object Request headers as Headers object or plain object {}
body string | FormData | Blob Request body. Not allowed for GET/HEAD. Auto-sets Content-Type. undefined
mode string Request mode: "cors", "no-cors", "same-origin" "cors"
credentials string Cookie handling: "omit", "same-origin", "include" "same-origin"
cache string Cache mode: "default", "no-store", "reload", "no-cache", "force-cache" "default"
redirect string Redirect mode: "follow", "error", "manual" "follow"
referrer string Referrer URL or "no-referrer" Document URL
integrity string Subresource Integrity hash for verification ""
signal AbortSignal AbortSignal to cancel request undefined
Response Property Type Description
ok boolean True if status is 200-299. Convenient for checking success.
status number HTTP status code (200, 404, 500, etc.)
statusText string HTTP status message ("OK", "Not Found", etc.)
headers Headers Response headers as Headers object
url string Final URL after redirects
redirected boolean True if response is result of redirect
type string Response type: "basic", "cors", "error", "opaque"
bodyUsed boolean True if body has been read. Body can only be read once.
Response Body Method Returns Description
json() Promise<any> Parses response body as JSON
text() Promise<string> Reads response body as text
blob() Promise<Blob> Reads response body as Blob (files, images)
arrayBuffer() Promise<ArrayBuffer> Reads response body as binary data
formData() Promise<FormData> Parses response body as FormData

Example: Basic fetch usage

// Simple GET request
fetch("/api/users")
  .then((response) => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then((data) => {
    console.log("Users:", data);
  })
  .catch((error) => {
    console.error("Fetch error:", error);
  });

// Async/await pattern (preferred)
async function fetchUsers() {
  try {
    const response = await fetch("/api/users");
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("Error:", error);
    throw error;
  }
}

// POST request with JSON
async function createUser(userData) {
  const response = await fetch("/api/users", {
    "method": "POST",
    "headers": {
      "Content-Type": "application/json"
    },
    "body": JSON.stringify(userData)
  });
  return response.json();
}

Example: Headers and credentials

// Using Headers object
const headers = new Headers();
headers.append("Authorization", "Bearer token123");
headers.append("Content-Type", "application/json");

const response = await fetch("/api/protected", {
  "method": "GET",
  "headers": headers,
  "credentials": "include" // Send cookies
});

// Check response headers
console.log("Content-Type:", response.headers.get("content-type"));
console.log("Has header:", response.headers.has("x-custom"));

// Iterate headers
for (let [key, value] of response.headers) {
  console.log(`${key}: ${value}`);
}

// FormData for file upload
const formData = new FormData();
formData.append("file", fileInput.files[0]);
formData.append("description", "Profile picture");

await fetch("/api/upload", {
  "method": "POST",
  "body": formData // Content-Type auto-set to multipart/form-data
});
Note: Fetch doesn't reject on HTTP errors (404, 500) - check response.ok or response.status. Body can only be read once - use response.clone() if you need to read it multiple times. Default credentials: "same-origin" doesn't send cookies to different origins.

2. Fetch API Advanced Patterns (AbortController, Streams)

Feature Syntax Description Use Case
AbortController new AbortController() Creates controller for aborting fetch requests. Has signal property and abort() method. Cancel requests
signal controller.signal AbortSignal to pass to fetch. Automatically aborts when controller.abort() called. Link abort to fetch
abort() controller.abort(reason) Aborts associated request. Optional reason passed to error handler. Trigger cancellation
ReadableStream response.body Response body as ReadableStream. Allows progressive reading of large responses. Stream large data
getReader() stream.getReader() Gets ReadableStreamDefaultReader to read chunks. Locks stream. Read stream chunks
read() reader.read() Returns Promise<{value, done}>. Value is Uint8Array chunk. Read next chunk

Example: Aborting fetch requests

// Basic abort pattern
const controller = new AbortController();
const signal = controller.signal;

fetch("/api/data", { signal })
  .then((response) => response.json())
  .then((data) => console.log(data))
  .catch((error) => {
    if (error.name === "AbortError") {
      console.log("Fetch aborted");
    } else {
      console.error("Fetch error:", error);
    }
  });

// Abort after 5 seconds
setTimeout(() => controller.abort(), 5000);

// Abort on user action
cancelButton.addEventListener("click", () => {
  controller.abort("User cancelled");
});

// Timeout utility
function fetchWithTimeout(url, options = {}, timeout = 5000) {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), timeout);
  
  return fetch(url, {
    ...options,
    "signal": controller.signal
  }).finally(() => clearTimeout(id));
}

// Usage
try {
  const response = await fetchWithTimeout("/api/slow", {}, 3000);
  const data = await response.json();
} catch (error) {
  if (error.name === "AbortError") {
    console.error("Request timed out");
  }
}

Example: Streaming response data

// Stream large file download with progress
async function downloadWithProgress(url) {
  const response = await fetch(url);
  const contentLength = response.headers.get("content-length");
  const total = parseInt(contentLength, 10);
  let loaded = 0;
  
  const reader = response.body.getReader();
  const chunks = [];
  
  while (true) {
    const { done, value } = await reader.read();
    
    if (done) break;
    
    chunks.push(value);
    loaded += value.length;
    const progress = (loaded / total) * 100;
    console.log(`Progress: ${progress.toFixed(2)}%`);
  }
  
  // Concatenate chunks into single Uint8Array
  const chunksAll = new Uint8Array(loaded);
  let position = 0;
  for (let chunk of chunks) {
    chunksAll.set(chunk, position);
    position += chunk.length;
  }
  
  return chunksAll;
}

// Stream text data line by line
async function streamText(url) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    const text = decoder.decode(value, { "stream": true });
    console.log("Chunk:", text);
  }
}

Example: Advanced patterns

// Request deduplication
const requestCache = new Map();

async function fetchOnce(url) {
  if (requestCache.has(url)) {
    return requestCache.get(url);
  }
  
  const promise = fetch(url).then((r) => r.json());
  requestCache.set(url, promise);
  
  try {
    return await promise;
  } catch (error) {
    requestCache.delete(url); // Remove failed request
    throw error;
  }
}

// Retry with exponential backoff
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      if (!response.ok && i < maxRetries - 1) {
        throw new Error(`HTTP ${response.status}`);
      }
      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
}

// Parallel requests with Promise.all
async function fetchMultiple(urls) {
  const promises = urls.map((url) => 
    fetch(url).then((r) => r.json())
  );
  return Promise.all(promises);
}

// Race condition - first to respond wins
async function fetchFastest(urls) {
  const promises = urls.map((url) => 
    fetch(url).then((r) => r.json())
  );
  return Promise.race(promises);
}
Warning: AbortController.abort() throws an error in the fetch promise - always catch it. Streams can only be read once - lock is not released until reader is closed. When streaming, make sure to handle errors and cleanup properly to avoid memory leaks.

3. XMLHttpRequest and Legacy AJAX Patterns

Property/Method Description Modern Alternative
new XMLHttpRequest() Creates XHR object for AJAX requests Use fetch()
open(method, url, async) Initializes request. Third parameter is async flag (default true). fetch(url, {method})
send(body) Sends request. Body for POST/PUT. fetch(url, {body})
abort() Aborts request in progress AbortController
setRequestHeader(name, value) Sets HTTP request header. Call after open(), before send(). fetch(url, {headers})
getResponseHeader(name) Gets response header value response.headers.get()
readyState Request state: 0=UNSENT, 1=OPENED, 2=HEADERS_RECEIVED, 3=LOADING, 4=DONE Promise states
status HTTP status code (200, 404, etc.) response.status
statusText HTTP status message response.statusText
responseText Response body as text response.text()
responseXML Response body as XML Document Parse with DOMParser
response Response body (type depends on responseType) Body reading methods
responseType Expected response type: "", "text", "json", "blob", "arraybuffer", "document" Body reading methods
timeout Timeout in milliseconds. 0 means no timeout. AbortSignal.timeout()
withCredentials Include cookies in cross-origin requests credentials: "include"
Event Description When Fired
loadstart Request started When request begins
progress Data transfer in progress Periodically while loading
load Request completed successfully When response received
error Request failed Network error occurred
abort Request was aborted When abort() called
timeout Request timed out Exceeded timeout duration
loadend Request finished (success or failure) After load/error/abort

Example: XMLHttpRequest basic usage (legacy)

// GET request
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/users", true);

xhr.onload = function() {
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
    console.log("Success:", data);
  } else {
    console.error("Error:", xhr.status);
  }
};

xhr.onerror = function() {
  console.error("Network error");
};

xhr.send();

// POST request with JSON
const xhr2 = new XMLHttpRequest();
xhr2.open("POST", "/api/users", true);
xhr2.setRequestHeader("Content-Type", "application/json");

xhr2.onreadystatechange = function() {
  if (xhr2.readyState === 4) { // DONE
    if (xhr2.status === 201) {
      console.log("Created:", JSON.parse(xhr2.responseText));
    }
  }
};

xhr2.send(JSON.stringify({ "name": "John" }));

// Upload with progress
const formData = new FormData();
formData.append("file", file);

const xhr3 = new XMLHttpRequest();
xhr3.upload.addEventListener("progress", (event) => {
  if (event.lengthComputable) {
    const percent = (event.loaded / event.total) * 100;
    console.log(`Upload: ${percent.toFixed(2)}%`);
  }
});

xhr3.open("POST", "/api/upload", true);
xhr3.send(formData);
Note: XMLHttpRequest is legacy API - use Fetch API for new projects. XHR still useful for upload progress tracking (Fetch doesn't support this natively yet). XHR requires more boilerplate code and callback-based error handling compared to Promise-based Fetch.

4. WebSocket API for Real-time Communication

Feature Syntax Description Browser Support
WebSocket Constructor new WebSocket(url, protocols) Creates WebSocket connection. URL must start with ws:// or wss://. Optional protocols array. All Browsers
send(data) ws.send(data) Sends data to server. Accepts string, Blob, ArrayBuffer, ArrayBufferView. All Browsers
close(code, reason) ws.close(code, reason) Closes connection. Optional close code and reason string. All Browsers
Property Type Description Values
readyState number Connection state 0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED
url string WebSocket URL Read-only
protocol string Negotiated subprotocol Read-only
bufferedAmount number Bytes queued but not yet transmitted Read-only
binaryType string Binary data type received "blob" or "arraybuffer"
Event Description Event Object Properties
open Connection established successfully Standard Event object
message Message received from server data: message content (string, Blob, ArrayBuffer)
error Error occurred Standard Event object
close Connection closed code: close code, reason: close reason, wasClean: boolean

Example: WebSocket basic usage

// Create WebSocket connection
const ws = new WebSocket("wss://example.com/socket");

// Connection opened
ws.addEventListener("open", (event) => {
  console.log("Connected to server");
  ws.send("Hello Server!");
});

// Listen for messages
ws.addEventListener("message", (event) => {
  console.log("Message from server:", event.data);
  
  // Handle different data types
  if (typeof event.data === "string") {
    const message = JSON.parse(event.data);
    handleMessage(message);
  } else if (event.data instanceof Blob) {
    // Handle binary data
    event.data.text().then((text) => console.log(text));
  }
});

// Handle errors
ws.addEventListener("error", (event) => {
  console.error("WebSocket error:", event);
});

// Connection closed
ws.addEventListener("close", (event) => {
  console.log("Connection closed:", event.code, event.reason);
  if (event.wasClean) {
    console.log("Clean close");
  } else {
    console.log("Connection died");
  }
});

// Send different data types
ws.send("Text message");
ws.send(JSON.stringify({ "type": "chat", "message": "Hello" }));
ws.send(new Blob(["binary data"]));
ws.send(new Uint8Array([1, 2, 3, 4]));

// Close connection gracefully
ws.close(1000, "Normal closure");

Example: WebSocket reconnection pattern

class WebSocketClient {
  constructor(url) {
    this.url = url;
    this.reconnectInterval = 1000;
    this.maxReconnectInterval = 30000;
    this.reconnectDecay = 1.5;
    this.connect();
  }
  
  connect() {
    this.ws = new WebSocket(this.url);
    
    this.ws.onopen = () => {
      console.log("WebSocket connected");
      this.reconnectInterval = 1000; // Reset on successful connection
    };
    
    this.ws.onmessage = (event) => {
      this.handleMessage(JSON.parse(event.data));
    };
    
    this.ws.onerror = (error) => {
      console.error("WebSocket error:", error);
    };
    
    this.ws.onclose = (event) => {
      console.log("WebSocket closed:", event.code);
      this.reconnect();
    };
  }
  
  reconnect() {
    console.log(`Reconnecting in ${this.reconnectInterval}ms...`);
    setTimeout(() => {
      this.connect();
      this.reconnectInterval = Math.min(
        this.reconnectInterval * this.reconnectDecay,
        this.maxReconnectInterval
      );
    }, this.reconnectInterval);
  }
  
  send(data) {
    if (this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(data));
    } else {
      console.warn("WebSocket not ready");
    }
  }
  
  handleMessage(data) {
    console.log("Received:", data);
  }
  
  close() {
    this.ws.close(1000, "Client closing");
  }
}

// Usage
const client = new WebSocketClient("wss://example.com/socket");
client.send({ "type": "subscribe", "channel": "updates" });
Note: Always use wss:// (secure WebSocket) in production, not ws://. Check readyState before calling send() to avoid errors. Implement reconnection logic for production applications. Use bufferedAmount to check if send buffer is full.

5. Server-Sent Events (EventSource) API

Feature Syntax Description Browser Support
EventSource Constructor new EventSource(url, options) Creates server-sent events connection. One-way: server to client only. Modern Browsers
close() eventSource.close() Closes connection. Cannot be reopened. Modern Browsers
Property Type Description Values
readyState number Connection state 0=CONNECTING, 1=OPEN, 2=CLOSED
url string Source URL Read-only
withCredentials boolean Whether to send credentials (cookies) Set in constructor options
Event Description When Fired
open Connection opened When connection established
message Message received from server Server sends data without event name
error Error occurred or connection lost Network error or server closed connection
Custom events Named events from server Server sends data with event: field

Example: EventSource basic usage

// Create EventSource connection
const eventSource = new EventSource("/api/events");

// Connection opened
eventSource.addEventListener("open", () => {
  console.log("SSE connection opened");
});

// Receive messages
eventSource.addEventListener("message", (event) => {
  console.log("Message:", event.data);
  const data = JSON.parse(event.data);
  updateUI(data);
});

// Custom named events from server
eventSource.addEventListener("notification", (event) => {
  const notification = JSON.parse(event.data);
  showNotification(notification);
});

eventSource.addEventListener("update", (event) => {
  const update = JSON.parse(event.data);
  console.log("Update received:", update);
});

// Handle errors
eventSource.addEventListener("error", (event) => {
  console.error("SSE error");
  if (eventSource.readyState === EventSource.CLOSED) {
    console.log("Connection closed");
  }
});

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

Example: Server-side SSE format (Node.js)

// Server sends events in this format:
// event: eventName
// data: JSON data
// id: unique id (optional)
// retry: milliseconds (optional)
// (blank line)

// Node.js server example
app.get("/api/events", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");
  
  // Send message without event name (uses 'message' event)
  res.write("data: " + JSON.stringify({ "message": "Hello" }) + "\n\n");
  
  // Send named event
  res.write("event: notification\n");
  res.write("data: " + JSON.stringify({ "title": "New message" }) + "\n");
  res.write("id: 123\n");
  res.write("\n");
  
  // Send periodic updates
  const interval = setInterval(() => {
    res.write(`event: update\n`);
    res.write(`data: ${JSON.stringify({ "time": Date.now() })}\n\n`);
  }, 1000);
  
  req.on("close", () => {
    clearInterval(interval);
    res.end();
  });
});
Note: EventSource automatically reconnects on connection loss (WebSocket doesn't). SSE is one-way only (server to client) - use WebSocket for bidirectional communication. SSE uses regular HTTP, works through most proxies and firewalls. Default retry timeout is 3 seconds.

6. Navigator.sendBeacon for Analytics

Feature Syntax Description Browser Support
sendBeacon navigator.sendBeacon(url, data) Sends asynchronous POST request that completes even if page is unloading. Returns boolean indicating if queued successfully. Modern Browsers
Data Type Description Content-Type
ArrayBuffer Binary data No Content-Type set
Blob Binary data with type Uses Blob's type property
FormData Form data multipart/form-data
URLSearchParams URL-encoded data application/x-www-form-urlencoded
String Text data text/plain

Example: sendBeacon usage patterns

// Track page unload
window.addEventListener("beforeunload", () => {
  const data = JSON.stringify({
    "event": "page_exit",
    "timestamp": Date.now(),
    "duration": performance.now()
  });
  
  const blob = new Blob([data], { "type": "application/json" });
  const queued = navigator.sendBeacon("/api/analytics", blob);
  
  if (!queued) {
    console.warn("Beacon not queued - data limit exceeded");
  }
});

// Track user actions
function trackEvent(eventName, properties) {
  const data = new URLSearchParams({
    "event": eventName,
    "timestamp": Date.now(),
    ...properties
  });
  
  navigator.sendBeacon("/api/track", data);
}

// Usage
trackEvent("button_click", { "button": "submit", "page": "/checkout" });

// Track errors
window.addEventListener("error", (event) => {
  const errorData = new FormData();
  errorData.append("message", event.message);
  errorData.append("filename", event.filename);
  errorData.append("lineno", event.lineno);
  errorData.append("colno", event.colno);
  
  navigator.sendBeacon("/api/errors", errorData);
});

// Track visibility changes
document.addEventListener("visibilitychange", () => {
  if (document.hidden) {
    const sessionData = JSON.stringify({
      "sessionId": sessionStorage.getItem("sessionId"),
      "duration": performance.now(),
      "interactionCount": getInteractionCount()
    });
    
    navigator.sendBeacon(
      "/api/session-end",
      new Blob([sessionData], { "type": "application/json" })
    );
  }
});
Note: sendBeacon is designed for analytics and diagnostics that must not be lost when page unloads. Request completes even if user closes tab/window. Cannot read response or handle errors. Has size limits (typically 64KB). Uses POST method only.
Warning: Don't use sendBeacon for critical data that requires confirmation - there's no way to know if request succeeded. Browsers may limit total beacon data size. Use Blob with proper Content-Type for JSON data, not plain string.

Network Communication Best Practices

  • Use Fetch API for modern HTTP requests - cleaner syntax and Promise-based
  • Always check response.ok or response.status - fetch doesn't reject on HTTP errors
  • Use AbortController for request cancellation and timeouts
  • Implement proper error handling with try/catch for async/await patterns
  • Use WebSocket for bidirectional real-time communication (chat, live updates)
  • Use EventSource for one-way server-to-client streaming (notifications, live feeds)
  • Implement reconnection logic for WebSocket connections in production
  • Use credentials: "include" to send cookies with cross-origin requests
  • Use navigator.sendBeacon for analytics during page unload - guaranteed delivery
  • Stream large responses with ReadableStream for memory efficiency and progress tracking