KAHIBARO
Discord Login Register

Request Bodies

Why Request Bodies Matter

So far, you have seen how to send information through the URL, such as path parameters and query parameters. That works well for simple, small bits of data, for example a page number or an ID.

However, many backend tasks require sending more complex data, such as:

Putting all of that into the URL would be unreadable, insecure, and sometimes impossible. This is where request bodies come in.

A request body is the part of an HTTP request that contains data sent from the client to the server, outside of the URL and headers.

Typical methods that use bodies:

Important rule:
The request body is where you send the main data of an HTTP request, especially for POST, PUT, and PATCH. Path and query parameters should be used only for identification, filtering, or simple options.

Where the Body Fits in an HTTP Request

An HTTP request has three main parts:

  1. Request line: method + path + version
    Example:
    POST /users HTTP/1.1
  2. Headers: extra metadata about the request
    Example:
    Content-Type: application/json
  3. Body: the actual data you send
    Example:
    {"name": "Alice", "email": "alice@example.com"}

In raw form, a request with a body might look like this:

http
POST /users HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 56
{"name":"Alice","email":"alice@example.com","age":30}

Note that there is an empty line between headers and the body. Everything after that empty line is the body.

Request Bodies vs Query and Path Parameters

Use this mental model:

Use CasePrefer
Identifying a single resourcePath parameter
Filtering, sorting, paginationQuery parameters
Main data for create/updateRequest body
File uploadsRequest body
Small flags / optionsQuery parameters or body

Examples:

  1. Get user with id 42
    • GET /users/42
      Path parameter 42 is enough. No body needed.
  2. List users on page 3, sorted by name
    • GET /users?page=3&sort=name
      Only query parameters. No body.
  3. Create a new user
    • POST /users with body:
      {"name": "Alice", "email": "alice@example.com"}
      The body holds the actual user data.
  4. Update a blog post
    • PUT /posts/10 with body:
      {"title": "New title", "content": "Updated content"}

Common Body Formats

The body is just bytes. To understand those bytes, the server must know what format they are in. This is what the Content-Type header is for.

Common formats:

Content-TypeTypical Use
application/jsonJSON APIs, REST APIs
application/x-www-form-urlencodedHTML forms, simple form data
multipart/form-dataFile uploads with forms
text/plainSimple raw text
application/xmlOlder systems, some APIs

For backend development today, you will mainly work with:

Other content types are used in special situations.

Important rule:
Always set the correct Content-Type header when sending a request body. The backend uses this header to decide how to parse the body.

JSON Request Bodies

JSON is the most common format for API request bodies.

Example: creating a new user

http
POST /users HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
  "name": "Alice",
  "email": "alice@example.com",
  "age": 30
}

Here:

From the backend perspective, in Python using FastAPI, you might define:

python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
    name: str
    email: str
    age: int
@app.post("/users")
def create_user(user: UserCreate):
    # 'user' contains data from the request body
    return {"message": f"User {user.name} created"}

The framework automatically:

If the client sends invalid JSON, the framework will reject the request.

Nested JSON in Bodies

Bodies can contain nested structures:

json
{
  "title": "My post",
  "content": "Hello world",
  "tags": ["intro", "hello"],
  "author": {
    "name": "Alice",
    "id": 123
  }
}

The backend must be prepared to parse and validate these nested objects.

Form-Encoded Request Bodies

When you submit a classic HTML form without files, browsers usually use:

Content-Type: application/x-www-form-urlencoded

Example HTML:

html
<form action="/login" method="post">
  <input type="text" name="username" />
  <input type="password" name="password" />
  <button type="submit">Login</button>
</form>

The browser sends:

http
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=alice&password=secret123

Notice:

On the backend, frameworks provide helpers to read this as form data, not as JSON.

In FastAPI:

python
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login")
def login(username: str = Form(...), password: str = Form(...)):
    # username and password come from the request body (form-encoded)
    return {"logged_in": True}

Multipart Form Data (Files and Fields)

When you upload files with a form, the browser uses:

Content-Type: multipart/form-data

This format allows:

Example HTML:

html
<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="text" name="description" />
  <input type="file" name="file" />
  <button type="submit">Upload</button>
</form>

The raw multipart body is quite complex, with boundaries, parts, and headers for each part. Frameworks handle this complexity for you.

In FastAPI:

python
from fastapi import FastAPI, File, UploadFile, Form
app = FastAPI()
@app.post("/upload")
def upload(
    description: str = Form(...),
    file: UploadFile = File(...)
):
    # 'description' is text from the body
    # 'file' is uploaded file data
    return {"filename": file.filename, "description": description}

Form data and file uploads are handled inside the request body, not in the URL.

Sending Request Bodies from Different Clients

Backend developers often need to test their endpoints. Here are examples using different tools.

Using curl

curl is a command-line tool to send HTTP requests.

  1. JSON body:
bash
curl -X POST http://localhost:8000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@example.com"}'
  1. Form body:
bash
curl -X POST http://localhost:8000/login \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=alice&password=secret123"
  1. Multipart with file upload:
bash
curl -X POST http://localhost:8000/upload \
  -F "description=Profile picture" \
  -F "file=@/path/to/image.jpg"

Note that you usually do not set Content-Type manually for multipart with -F. curl sets it for you.

Using JavaScript fetch

From a browser or frontend app:

  1. JSON body:
javascript
fetch('/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Alice',
    email: 'alice@example.com'
  })
});
  1. Form body:
javascript
const params = new URLSearchParams();
params.append('username', 'alice');
params.append('password', 'secret123');
fetch('/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: params.toString()
});
  1. Multipart with files:
javascript
const formData = new FormData();
formData.append('description', 'Profile picture');
formData.append('file', fileInput.files[0]);
fetch('/upload', {
  method: 'POST',
  body: formData  // browser sets Content-Type automatically
});

Combining Path, Query, and Body

You can receive data from all three sources at once.

Example endpoint: update a product

Request example:

http
PATCH /products/123?preview=true HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
  "price": 19.99,
  "name": "New Product Name"
}

In FastAPI:

python
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel
app = FastAPI()
class ProductUpdate(BaseModel):
    price: float | None = None
    name: str | None = None
@app.patch("/products/{product_id}")
def update_product(
    product_id: int = Path(...),
    preview: bool = Query(False),
    update: ProductUpdate = ...
):
    # product_id from path
    # preview from query
    # update from body
    return {
        "product_id": product_id,
        "preview": preview,
        "new_data": update.model_dump()
    }

Here each part has its own purpose:

Common Mistakes with Request Bodies

Beginners often run into similar issues.

Mistake 1: Missing or Wrong Content-Type

Example:

bash
curl -X POST http://localhost:8000/users \
  -d '{"name": "Alice"}'

If you forget -H "Content-Type: application/json", the server might:

Always set Content-Type to match the body format.

Mistake 2: Sending JSON but Not JSON.stringify in JavaScript

Wrong:

javascript
fetch('/users', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: { name: 'Alice', email: 'alice@example.com' }  // not a string
});

Right:

javascript
fetch('/users', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
});

The body must be a string when you send JSON.

Mistake 3: Using GET with a Body

Many tools and servers ignore or mishandle bodies in GET requests.

Even though the HTTP specification does not completely forbid bodies with GET, you should avoid them.

Important rule:
Do not send request bodies with GET requests. Use query parameters for simple data, or switch to POST if you must send a body.

Mistake 4: Putting Sensitive Data in the URL

Passwords, tokens, and private information should never go in the URL, because:

Use the request body for sensitive data instead.

Bad:

GET /login?username=alice&password=secret123

Better:

http
POST /login HTTP/1.1
Content-Type: application/json
{"username": "alice", "password": "secret123"}

Size and Limitations of Request Bodies

Request bodies can be large, for example when uploading files or sending big JSON documents. However, servers and proxies often have limits to:

Examples:

On the backend you can:

You will explore these topics later when learning about file handling and performance.

Summary

You now know:

In later chapters, you will see how to integrate request bodies with validation, models, and full REST API design.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!