KAHIBARO
Discord Login Register

6.7 JSON Requests

Understanding JSON Requests

When you build backend APIs, JSON requests are the most common way clients send data to your server. In this chapter you learn what JSON is in the context of HTTP, how clients send JSON, and how your backend should read, validate, and respond to JSON requests.


What Is JSON in HTTP Requests?

JSON stands for JavaScript Object Notation. It is a simple text format for representing structured data.

A JSON document is always text. For example:

json
{
  "name": "Alice",
  "age": 30,
  "is_admin": false,
  "skills": ["python", "sql"],
  "profile": {
    "twitter": "@alice",
    "website": "https://example.com"
  }
}

In HTTP, a JSON request means:

  1. The client sends a normal HTTP request.
  2. The request body contains JSON text.
  3. The Content-Type header says that the body is JSON.

For example, a raw HTTP request:

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

Your backend must:

  1. Read the bytes in the request body.
  2. Interpret them as text.
  3. Parse that text as JSON into data structures, for example a dictionary or list.
  4. Use that data in your application logic.

Content-Type: application/json

The Content-Type header tells your server how to interpret the request body.

For JSON requests, it must be:

http
Content-Type: application/json

Some clients also use:

http
Content-Type: application/json; charset=utf-8

Your backend should treat both as JSON.

Important rule
For JSON requests, always send
Content-Type: application/json in the request,
and on the server never try to parse a body as JSON if the content type does not indicate JSON.

If the header is missing or wrong, typical backend behavior:

Example of a 415 response:

http
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{
  "detail": "Content-Type application/xml is not supported. Use application/json."
}

JSON vs Other Request Body Types

In the previous chapter on form data you saw how HTML forms usually send data.

Here is how JSON compares to two common alternatives:

FeatureJSON (application/json)Form URL encoded (application/x-www-form-urlencoded)Multipart form (multipart/form-data)
Best forAPIs, structured data, nested objectsSimple form submissions, small key-value pairsFile uploads, mixed text and files
Body formatJSON textkey=value&key2=value2Binary with boundaries
Nested objectsEasy, naturalPossible but awkwardPossible, but more complex
File uploadsNot good, needs base64 or separate endpointNot suitableDesigned for this
Client side (JS)JSON.stringify(obj)URLSearchParams or FormDataFormData

For REST APIs:

Typical Use Cases for JSON Requests

JSON requests are used whenever you want to send structured data in an API:

http
  POST /users
  Content-Type: application/json
  {
    "name": "Alice",
    "email": "alice@example.com",
    "password": "secret123"
  }
http
  PUT /users/123
  Content-Type: application/json
  {
    "name": "Alice Doe",
    "email": "alice.doe@example.com"
  }
http
  PATCH /users/123
  Content-Type: application/json
  {
    "email": "alice.new@example.com"
  }
http
  POST /search
  Content-Type: application/json
  {
    "keywords": ["backend", "python"],
    "price_range": { "min": 10, "max": 100 },
    "sort_by": "created_at",
    "order": "desc"
  }

Valid vs Invalid JSON

JSON is strict. Small formatting errors make it invalid.

Valid JSON examples

json
{
  "name": "Alice",
  "age": 30,
  "is_admin": false,
  "skills": ["python", "sql"],
  "address": null
}
json
[1, 2, 3, 4]
json
{"value": 12.5}

Invalid JSON examples

json
{
  name: "Alice"          // keys must be in double quotes
}
json
{
  "age": 30,             // trailing comma not allowed
}
json
{
  "skills": ['python']   // strings must use double quotes, not single
}

If a client sends invalid JSON in a request, your backend should respond with a 400 Bad Request and a clear error message.

Example:

http
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "detail": "Invalid JSON in request body"
}

Reading JSON Requests in a Simple Python Server

You will use frameworks like FastAPI later, but it is useful to see what happens under the hood.

Imagine a very simple HTTP server built with Python standard library. Reading a JSON request body looks like this:

python
import json
def handle_request(env):
    # env is a dict-like object containing request info
    # 1. Check Content-Type
    content_type = env.get("CONTENT_TYPE", "")
    if "application/json" not in content_type:
        return 415, {"error": "Unsupported Media Type. Use application/json."}
    # 2. Read Content-Length
    try:
        length = int(env.get("CONTENT_LENGTH", 0))
    except ValueError:
        length = 0
    # 3. Read raw body bytes
    body_bytes = env["wsgi.input"].read(length)
    # 4. Decode to string
    body_str = body_bytes.decode("utf-8")
    # 5. Parse JSON
    try:
        data = json.loads(body_str)
    except json.JSONDecodeError:
        return 400, {"error": "Invalid JSON"}
    # Now data is a Python dict or list
    # Example logic:
    name = data.get("name")
    return 200, {"message": f"Hello, {name}!"}

Key steps:

  1. Check Content-Type.
  2. Read the correct number of bytes.
  3. Decode bytes to string using UTF 8.
  4. Use a JSON parser to convert string to objects.
  5. Handle parse errors.

JSON Request Examples with curl

curl is a command line tool to send HTTP requests. It is very useful to test JSON requests.

Sending JSON with POST

bash
curl -X POST "http://localhost:8000/users" \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@example.com"}'

Explanation:

Clean formatting using single quotes and pretty JSON

On Unix shells:

bash
curl -X POST "http://localhost:8000/users" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Alice",
    "email": "alice@example.com",
    "age": 30
  }'

On Windows PowerShell you often need double quotes outside and single quotes inside:

powershell
curl -Method POST "http://localhost:8000/users" `
  -Headers @{ "Content-Type" = "application/json" } `
  -Body '{"name": "Alice", "email": "alice@example.com", "age": 30}'

Common mistake

If you forget the Content-Type header:

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

Some servers will treat this as application/x-www-form-urlencoded and not as JSON. The body may not be parsed the way you expect.


JSON Requests in JavaScript (Fetch API)

Frontend applications often send JSON to your backend using fetch in the browser.

Sending JSON with fetch

javascript
const user = {
  name: "Alice",
  email: "alice@example.com"
};
fetch("https://api.example.com/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(user)
})
  .then(response => response.json())
  .then(data => {
    console.log("Server response:", data);
  })
  .catch(error => {
    console.error("Error:", error);
  });

Important parts:

Reading JSON response in JavaScript

Most JSON APIs also respond with JSON:

javascript
fetch("https://api.example.com/users/123")
  .then(response => {
    if (!response.ok) {
      throw new Error("Request failed: " + response.status);
    }
    return response.json();  // parse JSON response body
  })
  .then(user => {
    console.log("User:", user.name);
  })
  .catch(error => {
    console.error("Error:", error);
  });

Designing JSON Request Payloads

When you design an API, you decide what JSON structure clients must send.

Some principles:

  1. Use clear and consistent field names.
  2. Use appropriate data types.
  3. Use nested objects when it makes sense.
  4. Avoid sending unnecessary data.
  5. Separate input models from output models when needed.

Example: Creating a blog post

You might define the JSON request body for creating a blog post as:

json
{
  "title": "My first post",
  "content": "Hello backend world",
  "tags": ["backend", "learning"],
  "published": false
}

You can document this in human language:

Later, in validation chapters and in REST API documentation chapters you will see how to describe this more formally.


Validating JSON Request Bodies

After you parse JSON, you must validate it. Validation checks if the incoming data matches what your application expects.

Example: Manual validation in Python

python
import json
def create_user(env):
    # Read and parse JSON, simplified
    body = env["wsgi.input"].read(int(env.get("CONTENT_LENGTH", 0)))
    try:
        data = json.loads(body.decode("utf-8"))
    except json.JSONDecodeError:
        return 400, {"detail": "Invalid JSON"}
    errors = []
    # Check required fields
    if "email" not in data:
        errors.append({"field": "email", "message": "Email is required"})
    if "password" not in data:
        errors.append({"field": "password", "message": "Password is required"})
    # Type checks
    if "email" in data and not isinstance(data["email"], str):
        errors.append({"field": "email", "message": "Email must be a string"})
    if "age" in data and not isinstance(data["age"], int):
        errors.append({"field": "age", "message": "Age must be an integer"})
    if errors:
        return 422, {"detail": errors}
    # Use data safely now
    # ...
    return 201, {"message": "User created"}

Here:

You will later use libraries and frameworks to avoid doing all of this manually.


Nested JSON Objects and Arrays

JSON supports nested structures. Your API can accept complex request bodies.

Example: Order creation request

json
{
  "customer": {
    "name": "Alice",
    "email": "alice@example.com"
  },
  "items": [
    {
      "product_id": 1,
      "quantity": 2
    },
    {
      "product_id": 5,
      "quantity": 1
    }
  ],
  "shipping_address": {
    "line1": "123 Main St",
    "city": "Exampleville",
    "country": "US"
  },
  "notes": "Leave at the front door"
}

On the backend side, after parsing, this becomes a nested structure, for example in Python:

python
order["customer"]["name"]
order["items"][0]["product_id"]
order["shipping_address"]["city"]

When you design JSON, try to match the logical structure of the data in your system.


Handling Empty or Missing JSON Bodies

Sometimes a request with method POST, PUT, or PATCH might come with:

You should clearly define what your API expects.

Common patterns

Example:

http
PATCH /users/123
Content-Type: application/json
{}

If your API allows partial updates where all fields are optional, this might be valid and simply do nothing.


JSON and Character Encoding

JSON over HTTP almost always uses UTF 8 encoding.

Example JSON with non ASCII:

json
{
  "name": "José",
  "message": "こんにちは"
}

Your backend should:

Common JSON Request Mistakes and How to Handle Them

1. Missing Content-Type

Request:

http
POST /users
Content-Length: 34
{"name": "Alice", "email": "alice@example.com"}

Server should respond with something like:

http
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{
  "detail": "Content-Type application/json is required"
}

2. Invalid JSON syntax

Request body:

json
{ "name": "Alice", }

Trailing comma makes it invalid. Respond with 400 Bad Request and message about invalid JSON.

3. Wrong data types

Request:

json
{
  "name": "Alice",
  "age": "30"   // should be a number
}

Respond with 422 Unprocessable Entity and an error describing the invalid field.

4. Unexpected fields

Request:

json
{
  "username": "alice",   // API expects "name", not "username"
  "email": "alice@example.com",
  "extra": "something"
}

Depending on your API rules, you can:

It is better to be strict for public APIs.


JSON Requests and Idempotent Methods

You will learn more about HTTP methods and REST in later chapters. For JSON requests:

Example PUT with JSON:

http
PUT /users/123
Content-Type: application/json
{
  "name": "Alice",
  "email": "alice@example.com"
}

If you send this same JSON multiple times, the final state is the same as if you sent it once. That is idempotent behavior.


JSON Request Size and Limits

JSON requests can be large. Most servers and frameworks allow you to set a maximum body size.

Example policy:

Response example:

http
HTTP/1.1 413 Payload Too Large
Content-Type: application/json
{
  "detail": "Request body too large, max 1 MB"
}

Summary

Understanding JSON requests is essential for building modern APIs. In the next chapters you will connect this knowledge with response handling, templates, and full request response flows in a web framework.

Views: 9

Comments

Please login to add a comment.

Don't have an account? Register now!