Loading content...
Every interaction with an API begins with a request. Whether you're fetching data, creating a resource, or triggering an action, your request must be precisely constructed to communicate your intent clearly to the server.
A well-designed request format enables several critical outcomes:
This page provides a comprehensive exploration of how API requests are structured, the different ways data can be passed, and the best practices that distinguish amateur APIs from professional-grade systems.
By the end of this page, you will understand the complete anatomy of HTTP requests, the different types of parameters (path, query, header, body), popular request body formats, content negotiation, and best practices for designing request interfaces that are intuitive, secure, and maintainable.
An HTTP request is a structured text message that follows a precise format defined by the HTTP specification (RFC 9110). Understanding each component is essential for both consuming and designing APIs.
The Four Components of an HTTP Request:
12345678910111213141516
POST /api/v2/orders HTTP/1.1Host: api.example.comContent-Type: application/jsonAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...Accept: application/jsonContent-Length: 156X-Request-ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890 { "customer_id": 42, "items": [ {"product_id": 101, "quantity": 2}, {"product_id": 205, "quantity": 1} ], "shipping_address_id": 789}POST), the request target (/api/v2/orders), and the HTTP version (HTTP/1.1). This line tells the server what action to perform on which resource.Header-Name: value.Content-Type header.Request Target Formats:
The request target (URI) can take several forms:
| Form | Example | When Used |
|---|---|---|
| Origin-form | /api/users?active=true | Most common; path + query |
| Absolute-form | http://api.example.com/users | Used with proxies |
| Authority-form | api.example.com:443 | CONNECT method only (tunneling) |
| Asterisk-form | * | OPTIONS method for server capabilities |
In practice, virtually all API requests use the origin-form: the path portion of the URL optionally followed by a query string.
In HTTP/2 and HTTP/3, the request line doesn't exist as a separate line. Instead, the method, path, scheme, and authority are sent as pseudo-headers (:method, :path, :scheme, :authority). However, the logical components remain the same, and most HTTP clients abstract these differences.
API requests can carry data in four distinct locations, each serving different purposes. Choosing the right location for each piece of data is a critical design decision.
1. Path Parameters
Path parameters are embedded directly in the URL path. They identify specific resources.
1234567891011
URL Pattern: /users/{userId}/orders/{orderId}Actual Request: /users/42/orders/1001 Path parameters: userId = 42 orderId = 1001 Use cases: - Resource identification: /products/SKU-12345 - Hierarchy navigation: /organizations/acme/teams/engineering/members - Versioning: /api/v2/users (though v2 is often a path segment, not a parameter)Path Parameter Best Practices:
/users/42 over /users?id=42/orders/123 not /getOrder/1232. Query Parameters
Query parameters appear after the ? in the URL. They modify the request without changing the resource being addressed.
1234567891011121314151617
GET /api/products?category=electronics&min_price=100&max_price=500&sort=price&order=asc&limit=20&offset=40 Query parameters: category = electronics (filtering) min_price = 100 (filtering) max_price = 500 (filtering) sort = price (sorting) order = asc (sorting direction) limit = 20 (pagination: items per page) offset = 40 (pagination: skip items) Common query parameter patterns: Filtering: ?status=active&created_after=2024-01-01 Searching: ?q=wireless+headphones Pagination: ?page=3&per_page=25 or ?cursor=eyJpZCI6MTIzfQ== Field selection: ?fields=id,name,email Expansion: ?expand=author,commentsQuery Parameter Best Practices:
sort_by vs sortBy vs sort—pick one3. Header Parameters
Headers carry metadata about the request rather than the business payload.
| Header | Purpose | Example Value |
|---|---|---|
| Content-Type | Format of request body | application/json |
| Accept | Desired response format | application/json, text/html;q=0.9 |
| Authorization | Authentication credentials | Bearer eyJhbGciOiJIUzI1NiIs... |
| Accept-Language | Preferred language | en-US,en;q=0.9,es;q=0.8 |
| Accept-Encoding | Supported compression | gzip, deflate, br |
| Cache-Control | Caching behavior | no-cache |
| If-None-Match | Conditional request (ETag) | "abc123" |
| If-Modified-Since | Conditional request (date) | Sat, 15 Jan 2024 10:00:00 GMT |
| X-Request-ID | Request tracking | a1b2c3d4-e5f6-7890 |
| X-Api-Key | API key authentication | sk_live_abc123def456 |
The X- prefix for custom headers is deprecated (RFC 6648). Modern APIs should use app-specific prefixes like Stripe-Version or GitHub-Hookshot. Avoid generic names that might conflict with future standards.
4. Request Body
The request body carries the primary data payload for operations that create or modify resources. It's used with POST, PUT, and PATCH methods (and optionally DELETE).
| Location | When to Use | Examples |
|---|---|---|
| Path | Required resource identifiers | /users/42, /orders/1001 |
| Query | Optional modifiers, filters | ?status=active&limit=20 |
| Header | Request metadata, auth | Authorization, X-Request-ID |
| Body | Complex payloads, create/update data | JSON objects, form data |
The request body format is indicated by the Content-Type header. Different formats serve different purposes, and APIs may support multiple formats.
JSON (application/json)
JSON is the dominant format for modern API requests. It's human-readable, widely supported, and maps naturally to programming language data structures.
12345678910111213141516171819202122232425262728293031323334
// Simple object{ "username": "alice", "email": "alice@example.com", "password": "securePassword123"} // Nested structures{ "order": { "customer_id": 42, "items": [ { "product_id": 101, "quantity": 2, "options": { "color": "blue", "size": "L" } } ], "metadata": { "source": "mobile_app", "promo_code": "SAVE20" } }} // Arrays at root level (batch operations)[ {"id": 1, "status": "completed"}, {"id": 2, "status": "cancelled"}, {"id": 3, "status": "completed"}]Form URL-Encoded (application/x-www-form-urlencoded)
The traditional HTML form format. Values are encoded as key=value pairs, URL-encoded, and joined with &. Limited to flat key-value pairs.
1234
POST /oauth/token HTTP/1.1Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=abc123&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&client_id=app123Use cases for URL-encoded forms:
Multipart Form Data (multipart/form-data)
Used when requests contain files alongside regular data. Each part is separated by a boundary string and can have its own content type.
12345678910111213
POST /api/users/42/avatar HTTP/1.1Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="description" Profile photo update------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="avatar"; filename="photo.jpg"Content-Type: image/jpeg <binary file content>------WebKitFormBoundary7MA4YWxkTrZu0gW--Binary Formats
For high-performance internal APIs, binary formats reduce payload size and parsing overhead:
| Format | Content-Type | Human Readable | Best For |
|---|---|---|---|
| JSON | application/json | Yes | Most API payloads |
| URL-encoded | application/x-www-form-urlencoded | Yes | OAuth, simple forms |
| Multipart | multipart/form-data | Partly | File uploads |
| XML | application/xml | Yes | Enterprise/SOAP APIs |
| Protocol Buffers | application/protobuf | No | gRPC, high-performance |
| MessagePack | application/msgpack | No | JSON-like but binary |
Content negotiation is the mechanism by which clients and servers agree on content formats. It allows a single endpoint to serve different representations of the same resource.
Request-Side Negotiation (Client Preferences):
Clients express preferences through headers:
12345
GET /api/products/123 HTTP/1.1Accept: application/json, application/xml;q=0.8, */*;q=0.1Accept-Language: en-US, en;q=0.9, es;q=0.8, fr;q=0.7Accept-Encoding: gzip, deflate, brAccept-Charset: UTF-8, ISO-8859-1;q=0.5q=0.8) indicate relative preference. Higher values (max 1.0) are preferred.Quality Values (q-values):
Quality values range from 0 to 1 and indicate preference weight:
Accept: application/json, application/xml;q=0.8, text/plain;q=0.5, */*;q=0.1
Interpretation:
Server-Side Response:
Servers respond with the negotiated format and indicate what was served:
1234567
HTTP/1.1 200 OKContent-Type: application/json; charset=utf-8Content-Language: en-USContent-Encoding: gzipVary: Accept, Accept-Language, Accept-Encoding {"id": 123, "name": "Widget", "price": 29.99}The Vary response header tells caches which request headers affect the response. If a response varies by Accept, caches must store separate versions for JSON and XML requests. Missing or incorrect Vary headers cause cache corruption.
406 Not Acceptable:
If the server cannot satisfy any of the client's content preferences, it should return 406 Not Acceptable with a list of available alternatives:
HTTP/1.1 406 Not Acceptable
Content-Type: application/json
{
"error": "not_acceptable",
"message": "Cannot provide response in requested format",
"available_formats": ["application/json", "application/xml"]
}
Robust APIs validate all incoming requests before processing. Good validation provides security, prevents errors, and gives clients actionable feedback.
Validation Layers:
JSON Schema for Validation:
JSON Schema provides a declarative way to specify validation rules:
1234567891011121314151617181920212223242526272829303132
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["email", "password"], "properties": { "email": { "type": "string", "format": "email", "maxLength": 255 }, "password": { "type": "string", "minLength": 8, "maxLength": 128 }, "username": { "type": "string", "pattern": "^[a-zA-Z][a-zA-Z0-9_]{2,29}$", "description": "3-30 chars, starts with letter, alphanumeric + underscore" }, "roles": { "type": "array", "items": { "type": "string", "enum": ["admin", "editor", "viewer"] }, "uniqueItems": true, "maxItems": 5 } }, "additionalProperties": false}Error responses should be specific, actionable, and secure. Indicate which field failed and why, but don't leak sensitive information. Don't say 'User with this email exists' if that reveals account existence—say 'Invalid credentials' for login failures.
Example Validation Error Response:
1234567891011121314151617181920212223
{ "error": "validation_error", "message": "Request validation failed", "details": [ { "field": "email", "code": "invalid_format", "message": "Must be a valid email address" }, { "field": "password", "code": "too_short", "message": "Must be at least 8 characters", "context": {"minimum": 8, "actual": 5} }, { "field": "roles[2]", "code": "invalid_enum", "message": "Must be one of: admin, editor, viewer", "context": {"allowed": ["admin", "editor", "viewer"], "received": "superuser"} } ]}Understanding idempotency and safety is crucial for reliable API design. These properties affect how clients can retry requests and how servers handle duplicates.
Definitions:
| Method | Safe | Idempotent | Explanation |
|---|---|---|---|
| GET | Yes | Yes | Reading data never modifies state |
| HEAD | Yes | Yes | Like GET, but no response body |
| OPTIONS | Yes | Yes | Queries server capabilities |
| PUT | No | Yes | Repeated PUTs to same resource yield same result |
| DELETE | No | Yes | Deleting twice = deleting once (resource is gone) |
| POST | No | No | Each POST may create a new resource |
| PATCH | No | No* | Depends on patch semantics |
Why Idempotency Matters:
Network communication is unreliable. Requests can timeout, connections can drop mid-response, and clients can't always know if the server processed a request.
Scenario without idempotency:
Solution: Idempotency Keys
For non-idempotent operations, clients can provide idempotency keys:
12345
POST /api/orders HTTP/1.1Content-Type: application/jsonIdempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890 {"customer_id": 42, "items": [{"product_id": 101, "quantity": 2}]}Server Implementation:
On first request with an idempotency key:
On duplicate request with same key:
Best Practices:
Where possible, make operations inherently idempotent through design. Use PUT with full state replacement instead of POST. Use 'set to X' instead of 'increment by Y'. When increment-style operations are necessary, idempotency keys are essential.
Request design directly impacts performance. Large requests consume bandwidth, slow down mobile clients, and strain server resources.
Practical Limits:
| Component | Practical Limit | Impact of Exceeding |
|---|---|---|
| URL Length | ~2,000 chars | Some browsers/proxies reject; use POST instead |
| Total Headers | 8-16 KB | Server rejection (431 status) |
| Request Body | 1-10 MB typical | Server rejection (413 status); use chunked/streaming |
| Individual Header | 4-8 KB | May be rejected by proxies |
| Cookie Header | 4 KB per domain | Browser limitation; can't exceed |
Optimization Strategies:
1. Request Compression
Clients can compress request bodies to reduce transfer time:
12345
POST /api/data HTTP/1.1Content-Type: application/jsonContent-Encoding: gzip <gzip-compressed JSON body>2. Batch Requests
Instead of N individual requests, combine into one batch request:
1234567891011
// Instead of 100 separate POST /api/events requests:POST /api/events/batch { "events": [ {"type": "page_view", "page": "/home", "timestamp": "2024-01-15T10:30:00Z"}, {"type": "click", "element": "signup_button", "timestamp": "2024-01-15T10:30:05Z"}, {"type": "page_view", "page": "/signup", "timestamp": "2024-01-15T10:30:06Z"} // ... up to 100 events ]}?fields=id,name)Understanding request formats is foundational for both consuming and designing APIs. Properly structured requests enable clear communication, efficient validation, and reliable processing.
What's Next:
Now that we understand how to construct API requests, the next page explores Response Formats—how servers structure responses, status code semantics, error handling patterns, and the design principles that make API responses clear, consistent, and helpful.
You now understand the complete anatomy of HTTP requests, parameter placement strategies, body formats, content negotiation, validation approaches, and idempotency patterns. This knowledge enables you to construct precise API requests and design intuitive request interfaces.