httpapinetwork

HTTP Tools for Developers: Status Codes, Headers, and Request Building

· Cosyslabs

HTTP (HyperText Transfer Protocol) defines how clients and servers communicate over the web. Every API call, web page load, and file download is an HTTP exchange. Understanding status codes, headers, authentication schemes, and caching directives is fundamental to building and debugging web applications.

HTTP Methods

MethodIdempotentSafeCommon Use
GETYesYesRetrieve resource
HEADYesYesGet headers without body
OPTIONSYesYesCheck CORS/capabilities
POSTNoNoCreate resource, submit data
PUTYesNoReplace entire resource
PATCHNoNoPartial update
DELETEYesNoRemove resource

Idempotent means repeating the request produces the same result. Safe means no side effects (read-only).

HTTP Status Codes

1xx — Informational

CodeNameWhen Used
100ContinueClient should send request body
101Switching ProtocolsWebSocket upgrade
103Early HintsPreload hints before final response

2xx — Success

CodeNameWhen Used
200OKStandard success
201CreatedResource successfully created (POST)
202AcceptedRequest accepted, processing async
204No ContentSuccess, no body (DELETE, PUT)
206Partial ContentRange request fulfilled

3xx — Redirection

CodeNameWhen Used
301Moved PermanentlySEO-friendly permanent redirect
302FoundTemporary redirect (deprecated — use 307/308)
303See OtherRedirect to GET after POST (PRG pattern)
304Not ModifiedCache is still valid (conditional GET)
307Temporary RedirectTemporary, preserves method
308Permanent RedirectPermanent, preserves method

4xx — Client Errors

CodeNameCommon Cause
400Bad RequestInvalid syntax, missing required field
401UnauthorizedMissing or invalid authentication
403ForbiddenAuthenticated but lacks permission
404Not FoundResource does not exist
405Method Not AllowedWrong HTTP method
408Request TimeoutClient took too long
409ConflictState conflict (duplicate, optimistic lock)
410GonePermanently removed (SEO signal)
413Content Too LargePayload exceeds server limit
415Unsupported Media TypeWrong Content-Type
422Unprocessable EntitySyntactically valid but semantically wrong
429Too Many RequestsRate limit exceeded

5xx — Server Errors

CodeNameCommon Cause
500Internal Server ErrorUnhandled exception
501Not ImplementedMethod not supported
502Bad GatewayUpstream server returned invalid response
503Service UnavailableServer overloaded or down
504Gateway TimeoutUpstream server timed out

Request Headers

GET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Content-Type: application/json
Content-Length: 82
User-Agent: MyApp/1.0 (Linux; x86_64)
X-Request-ID: f47ac10b-58cc-4372-a567-0e02b2c3d479
X-Api-Key: sk_live_abc123
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Response Headers

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 1024
Content-Encoding: gzip
Cache-Control: max-age=3600, must-revalidate
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Mon, 15 Jun 2026 10:00:00 GMT
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1750000000
Vary: Accept-Encoding, Accept-Language
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff

Authentication Schemes

Bearer Token (JWT)

Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
const response = await fetch("/api/data", {
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

Basic Authentication

Authorization: Basic dXNlcjpwYXNzd29yZA==

The value is Base64(username:password). Always requires HTTPS.

const credentials = btoa(`${username}:${password}`);
fetch("/api", {
  headers: { Authorization: `Basic ${credentials}` },
});

API Key

Varies by API — commonly sent as header or query parameter:

X-Api-Key: sk_live_abc123xyz
# or
Authorization: ApiKey sk_live_abc123xyz

OAuth 2.0

OAuth 2.0 uses Bearer tokens obtained through various flows (authorization code, client credentials, device code):

// Client credentials flow (server-to-server)
const tokenResponse = await fetch("https://auth.example.com/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "client_credentials",
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    scope: "read:users write:posts",
  }),
});
const { access_token } = await tokenResponse.json();

Caching Headers

Cache-Control

Cache-Control: no-store              # Never cache (sensitive data)
Cache-Control: no-cache              # Cache but revalidate every request
Cache-Control: max-age=3600          # Cache for 1 hour
Cache-Control: s-maxage=86400        # CDN cache for 1 day
Cache-Control: max-age=0, must-revalidate  # Must revalidate expired cache
Cache-Control: public, max-age=31536000, immutable  # CDN-cacheable forever

ETag and Conditional Requests

# First request
GET /api/data HTTP/1.1

# Response includes ETag
HTTP/1.1 200 OK
ETag: "abc123"

# Subsequent request — client sends ETag back
GET /api/data HTTP/1.1
If-None-Match: "abc123"

# If unchanged — server returns 304 with no body
HTTP/1.1 304 Not Modified

CORS

CORS (Cross-Origin Resource Sharing) controls which origins can make requests to your API from browsers.

# Browser sends preflight OPTIONS request for complex requests
OPTIONS /api/data HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

# Server response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400  # Cache preflight for 24 hours
Access-Control-Allow-Credentials: true
// Express CORS middleware
import cors from "cors";

app.use(cors({
  origin: ["https://app.example.com", "https://admin.example.com"],
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
  credentials: true,
  maxAge: 86400,
}));

Rate Limiting Headers

Standard rate limit headers (no official RFC, but widely adopted conventions):

X-RateLimit-Limit: 100        # Total requests allowed per window
X-RateLimit-Remaining: 23     # Requests remaining this window
X-RateLimit-Reset: 1750000000 # Unix timestamp when window resets

# GitHub-style
X-RateLimit-Used: 77

# IETF Draft standard headers
RateLimit-Limit: 100
RateLimit-Remaining: 23
RateLimit-Reset: 1750000000

When rate limited, servers should return 429 Too Many Requests with:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Content Negotiation

# Client requests preferred formats in priority order
Accept: application/json, text/html;q=0.9, */*;q=0.8

# Client requests preferred languages
Accept-Language: en-US,en;q=0.9,fr;q=0.7

# Client declares what encodings it accepts
Accept-Encoding: gzip, deflate, br, zstd

Security Headers

# Prevent clickjacking
X-Frame-Options: DENY

# Prevent MIME type sniffing
X-Content-Type-Options: nosniff

# Enforce HTTPS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

# Control browser features
Permissions-Policy: camera=(), microphone=(), geolocation=()

# Content Security Policy
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self'

# Referrer Policy
Referrer-Policy: strict-origin-when-cross-origin

Debugging HTTP Requests

curl

# GET with headers
curl -H "Authorization: Bearer TOKEN" -v https://api.example.com/users

# POST with JSON body
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer TOKEN" \
  -d '{"name": "Alice", "email": "alice@example.com"}' \
  https://api.example.com/users

# Show only response headers
curl -I https://api.example.com/users

# Follow redirects
curl -L https://example.com/redirect

JavaScript (fetch)

// Full request with error handling
async function apiCall(path, options = {}) {
  const response = await fetch(`https://api.example.com${path}`, {
    ...options,
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${getToken()}`,
      ...options.headers,
    },
  });
  
  if (response.status === 429) {
    const retryAfter = response.headers.get("Retry-After");
    throw new Error(`Rate limited. Retry after ${retryAfter}s`);
  }
  
  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new Error(error.message ?? `HTTP ${response.status}`);
  }
  
  return response.json();
}

Tools