REST API Development

Request & Response Formats

18 min Lesson 4 of 35

Understanding Data Formats in REST APIs

REST APIs need a common language to exchange data between clients and servers. While REST itself doesn't mandate a specific format, JSON has become the de facto standard due to its simplicity, readability, and universal support across programming languages.

Note: While this lesson covers multiple formats, 95% of modern REST APIs use JSON exclusively. Focus on mastering JSON structure and best practices.

JSON: The King of API Data Formats

JSON (JavaScript Object Notation) is lightweight, human-readable, and easy to parse. It's the standard for modern REST APIs.

JSON Basics:

{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "age": 30,
  "isActive": true,
  "roles": ["user", "editor"],
  "address": {
    "street": "123 Main St",
    "city": "New York",
    "zipCode": "10001"
  },
  "metadata": null
}

JSON Data Types:

  • String: "text in double quotes"
  • Number: 123, 45.67 (no quotes)
  • Boolean: true, false (lowercase, no quotes)
  • Array: ["item1", "item2"]
  • Object: {"key": "value"}
  • Null: null (represents absence of value)
Warning: JSON doesn't support comments, trailing commas, or single quotes. Always validate your JSON with a linter before deploying.

Structuring JSON Responses

Consistent response structure makes your API predictable and easy to use.

Single Resource Response:

GET /api/users/123

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com",
    "created_at": "2026-01-15T10:30:00Z",
    "updated_at": "2026-02-14T14:20:00Z"
  }
}

Collection Response:

GET /api/users?page=1&limit=2

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": 123,
      "name": "John Doe",
      "email": "john@example.com"
    },
    {
      "id": 124,
      "name": "Jane Smith",
      "email": "jane@example.com"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 2,
    "total": 150,
    "total_pages": 75
  },
  "links": {
    "first": "/api/users?page=1",
    "prev": null,
    "next": "/api/users?page=2",
    "last": "/api/users?page=75"
  }
}

Error Response:

POST /api/users

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request data failed validation",
    "details": [
      {
        "field": "email",
        "message": "Email is required",
        "code": "REQUIRED_FIELD"
      },
      {
        "field": "age",
        "message": "Age must be at least 18",
        "code": "MIN_VALUE"
      }
    ]
  }
}
Tip: Wrap your response data in a "data" object even for single resources. This allows you to add metadata later without breaking clients.

JSON Naming Conventions

Choose a naming style and stick to it throughout your API.

camelCase (Recommended for JavaScript-heavy APIs):

{
  "userId": 123,
  "firstName": "John",
  "lastName": "Doe",
  "emailAddress": "john@example.com",
  "isEmailVerified": true,
  "createdAt": "2026-01-15T10:30:00Z"
}

snake_case (Common in Python/Ruby APIs):

{
  "user_id": 123,
  "first_name": "John",
  "last_name": "Doe",
  "email_address": "john@example.com",
  "is_email_verified": true,
  "created_at": "2026-01-15T10:30:00Z"
}

PascalCase (Rare in REST APIs):

{
  "UserId": 123,
  "FirstName": "John",
  "LastName": "Doe"
}
Important: JavaScript and TypeScript developers prefer camelCase. Python and Ruby developers prefer snake_case. Pick what fits your primary client base, but be consistent.

Date and Time Formats

Always use ISO 8601 format for dates and times. It's unambiguous and universally supported.

ISO 8601 Examples:

// Date only
"2026-02-14"

// Date and time (UTC - recommended)
"2026-02-14T10:30:00Z"

// Date and time with timezone offset
"2026-02-14T10:30:00-05:00"

// Date and time with milliseconds
"2026-02-14T10:30:00.123Z"
Tip: Always store and transmit dates in UTC (denoted by Z). Let clients convert to their local timezone for display.

Null vs. Missing Fields

Decide how to handle missing data and be consistent.

Option 1: Include Null Values

{
  "id": 123,
  "name": "John Doe",
  "middleName": null,
  "phone": null,
  "bio": null
}

Pros:
✅ Explicit about missing data
✅ Client knows field exists
✅ Easier schema validation

Cons:
❌ Larger response size
❌ More verbose

Option 2: Omit Null Values

{
  "id": 123,
  "name": "John Doe"
}

Pros:
✅ Smaller response size
✅ Cleaner, less cluttered

Cons:
❌ Can't distinguish between null and undefined
❌ Client must handle missing keys

HTTP Headers: The Metadata Layer

Headers provide crucial information about requests and responses without cluttering the body.

Content-Type Header

Tells the server/client what format the data is in.

// Request
POST /api/users
Content-Type: application/json

{"name": "John Doe"}

// Response
HTTP/1.1 200 OK
Content-Type: application/json

{"id": 123, "name": "John Doe"}

Accept Header

Client tells server what formats it can handle.

// Client prefers JSON
GET /api/users
Accept: application/json

// Client can handle multiple formats (preference order)
GET /api/users
Accept: application/json, application/xml;q=0.9, */*;q=0.8
Quality Values (q): The q parameter (0-1) indicates preference. Higher values = higher preference. Default is q=1.0.

Common Content Types:

Content-Type Description Usage
application/json JSON data 99% of REST APIs
application/xml XML data Legacy systems
application/x-www-form-urlencoded Form data HTML forms
multipart/form-data File uploads Images, documents
text/plain Plain text Simple responses
text/html HTML document API documentation

Content Negotiation

Content negotiation allows the same endpoint to return different formats based on client preference.

Server-Driven Negotiation:

// Client requests JSON
GET /api/users/123
Accept: application/json

Response:
HTTP/1.1 200 OK
Content-Type: application/json

{"id": 123, "name": "John Doe"}

// Client requests XML
GET /api/users/123
Accept: application/xml

Response:
HTTP/1.1 200 OK
Content-Type: application/xml

<user>
  <id>123</id>
  <name>John Doe</name>
</user>

Handling Unsupported Formats:

GET /api/users/123
Accept: application/pdf

Response:
HTTP/1.1 406 Not Acceptable
Content-Type: application/json

{
  "error": {
    "code": "UNSUPPORTED_MEDIA_TYPE",
    "message": "Server cannot produce response in requested format",
    "supported_formats": ["application/json", "application/xml"]
  }
}

XML: The Alternative Format

While JSON dominates, some enterprise systems still use XML.

XML Example:

<?xml version="1.0" encoding="UTF-8"?>
<user>
  <id>123</id>
  <name>John Doe</name>
  <email>john@example.com</email>
  <roles>
    <role>user</role>
    <role>editor</role>
  </roles>
  <address>
    <street>123 Main St</street>
    <city>New York</city>
  </address>
</user>

JSON vs. XML Comparison:

Aspect JSON XML
Readability Very readable Verbose
Size Smaller (30-50% less) Larger
Parsing Speed Faster Slower
Data Types Native types Everything is text
Arrays Native support Repeated elements
Validation JSON Schema XSD, DTD
Comments Not supported Supported
Warning: Unless you have a specific requirement (legacy systems, enterprise integration), stick with JSON. XML adds unnecessary complexity for most REST APIs.

File Uploads: multipart/form-data

When uploading files, use multipart/form-data instead of JSON.

POST /api/users/123/avatar
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="avatar.jpg"
Content-Type: image/jpeg

[binary file data]
------WebKitFormBoundary
Content-Disposition: form-data; name="description"

New profile picture
------WebKitFormBoundary--

Response:
HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "id": 456,
    "filename": "avatar.jpg",
    "size": 51234,
    "url": "https://cdn.example.com/avatars/456.jpg",
    "uploaded_at": "2026-02-14T10:30:00Z"
  }
}

Compression: Reducing Bandwidth

Enable compression to reduce response sizes by 60-80%.

// Client accepts compressed response
GET /api/users
Accept-Encoding: gzip, deflate, br

// Server sends compressed response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Content-Length: 1234

[compressed data]
Tip: Most web servers (Nginx, Apache) and frameworks (Express, Laravel) support automatic compression. Enable it in production to significantly reduce bandwidth costs.

Character Encoding: UTF-8 Always

Always use UTF-8 encoding to support international characters.

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "name": "José García",
  "city": "São Paulo",
  "greeting": "你好",
  "message": "مرحبا"
}

Best Practices Checklist

  • ✅ Use JSON as your primary format
  • ✅ Always set Content-Type headers correctly
  • ✅ Use ISO 8601 for all dates and times
  • ✅ Be consistent with naming (camelCase or snake_case)
  • ✅ Wrap responses in "data" object for flexibility
  • ✅ Include pagination metadata for collections
  • ✅ Provide detailed error messages with codes
  • ✅ Support compression (gzip, brotli)
  • ✅ Use UTF-8 encoding everywhere
  • ✅ Return 406 for unsupported Accept types
Exercise: Structure API Responses

Create proper JSON response structures for these scenarios:

  1. Successful user creation: User ID 789, name "Alice Johnson", email "alice@example.com", created today at 10:30 AM UTC
  2. Validation error: Email is invalid, password is too short (min 8 characters)
  3. Collection with pagination: 3 products out of 150 total, page 1 of 50, 3 items per page

Sample Solution for #1:

HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/users/789

{
  "data": {
    "id": 789,
    "name": "Alice Johnson",
    "email": "alice@example.com",
    "created_at": "2026-02-14T10:30:00Z"
  }
}

Key Takeaways

  • JSON is the standard format for modern REST APIs
  • Always use Content-Type and Accept headers correctly
  • ISO 8601 format for dates (UTC with Z suffix)
  • Be consistent with naming conventions throughout your API
  • Wrap responses in "data" object for future flexibility
  • Include helpful metadata (pagination, timestamps)
  • Support compression to reduce bandwidth
  • Use UTF-8 encoding for international support
Next Lesson Preview: You've learned the theory - now it's time to build! In the next lesson, we'll create your first REST API from scratch, implementing everything you've learned so far.