Making Requests
A request is made up of several parts — the URL, method, headers, and optionally a body. Understanding each part gives you complete control over how you talk to any API.
Anatomy of an HTTP Request
METHOD + URL
GET /api/training/users?limit=5&offset=0
HEADERS
Content-Type: application/json
Authorization: Bearer your-api-key-here
Accept: application/json
BODY (POST/PUT/PATCH only)
{
"name": "Jane Doe",
"email": "[email protected]"
}Query Parameters
Query parameters are added to the URL after a ? and let you filter, sort, or paginate results. Multiple params are separated by &.
Get only the first 3 users (pagination)
Skip the first 5, get the next 5 (page 2)
Search for users with "alice" in their name or email
Get only posts that belong to user 1
Get only incomplete todos
Get posts tagged "api", limited to 5
Request Headers
Headers carry metadata about your request. They're separate from the URL and the body — think of them as the envelope that wraps your letter.
| Header | Purpose | Example |
|---|---|---|
| Content-Type | Format of the request body you're sending | application/json |
| Accept | Format you want the response in | application/json |
| Authorization | Who you are (auth token or API key) | Bearer eyJhbGc... |
| X-API-Key | Common pattern for API key authentication | sk_live_abc123 |
| User-Agent | Identifies what client is making the request | MyApp/1.0 |
Request Body
For POST, PUT, and PATCH requests, you send data in the request body. With JSON APIs, you serialize your data as JSON and set Content-Type: application/json.
// Creating a new user with fetch()
const response = await fetch('/api/training/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Jane Doe',
email: '[email protected]',
city: 'Minneapolis',
}),
});
const result = await response.json();
console.log(result.data); // { id: 11, name: 'Jane Doe', ... }Authentication Basics
Most real-world APIs require authentication to know who's making requests. Our training API is open (no auth required) so you can focus on learning. But here's what you'll encounter in the wild:
API Keys
Most CommonA long secret string you include in every request. Usually in a header like Authorization: Bearer KEY or X-API-Key: KEY.
// API key in a header
fetch('/api/data', {
headers: { 'X-API-Key': 'sk_live_your_key_here' }
})Bearer Tokens (JWT)
Very CommonYou log in first and get a token back. Then include that token in every subsequent request.
// Bearer token after login
fetch('/api/me', {
headers: { 'Authorization': 'Bearer eyJhbGc...' }
})Basic Auth
Older PatternEncodes username:password in base64. Simple but less secure. Rarely used in modern APIs.
// Basic auth (base64 username:password)
fetch('/api/data', {
headers: {
'Authorization': 'Basic ' + btoa('user:password')
}
})Putting It All Together
Here's a complete, real-world fetch call that demonstrates everything in this module:
async function updateUserCity(userId, newCity) {
const response = await fetch(`/api/training/users/${userId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
// No auth needed for training API
},
body: JSON.stringify({ city: newCity }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const result = await response.json();
return result.data; // updated user object
}
// Try it:
const updated = await updateUserCity(1, 'Nashville');
console.log(updated.city); // 'Nashville'