Not started
🚀 Module 4 of 5

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 &.

/api/training/users?limit=3

Get only the first 3 users (pagination)

/api/training/users?offset=5&limit=5

Skip the first 5, get the next 5 (page 2)

/api/training/users?search=alice

Search for users with "alice" in their name or email

/api/training/posts?userId=1

Get only posts that belong to user 1

/api/training/todos?completed=false

Get only incomplete todos

/api/training/posts?tag=api&limit=5

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.

HeaderPurposeExample
Content-TypeFormat of the request body you're sendingapplication/json
AcceptFormat you want the response inapplication/json
AuthorizationWho you are (auth token or API key)Bearer eyJhbGc...
X-API-KeyCommon pattern for API key authenticationsk_live_abc123
User-AgentIdentifies what client is making the requestMyApp/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 Common

A 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 Common

You 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 Pattern

Encodes 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'