FastAPI Basics • Lesson 25

Schema Extra - Examples

Provide example data for your API documentation using Pydantic model_config and OpenAPI examples.

🎯 What You'll Learn

  • Add example data to Pydantic models with json_schema_extra
  • Use openapi_examples parameter in Body() for multiple examples
  • Understand how examples appear in auto-generated API docs
  • Provide realistic sample data for better API documentation

Schema Extra - Examples

🎯 What You'll Learn

In this lesson you will learn how to enrich your API documentation with realistic example data. Well-crafted examples make it easier for consumers to understand your API without reading lengthy descriptions.

By the end of this lesson, you'll be able to:

  • Add example data to Pydantic models using model_config with json_schema_extra
  • Attach per-field examples with the Field() function
  • Provide multiple named examples via the Body() openapi_examples parameter
  • Understand how Swagger UI and ReDoc render those examples automatically

📚 Theory

Why Examples Matter

When developers explore your API through the interactive documentation (Swagger UI or ReDoc), the first thing they look at is the example request body. Without examples the docs show only field names and types, leaving consumers guessing about realistic values.

Good examples:

  • Remove ambiguity about expected formats (e.g. "Is price in cents or dollars?")
  • Allow one-click "Try it out" in Swagger UI with pre-filled data
  • Serve as living documentation that stays in sync with your code
  • Help frontend teams integrate faster by providing concrete payloads

FastAPI passes example data straight into the generated OpenAPI schema, so Swagger UI and ReDoc pick it up automatically.

🔧 Key Concepts

There are three main approaches for adding examples in FastAPI. Each one targets a different level of granularity.


1. model_config with json_schema_extra

This is the model-level approach. You embed one or more full examples directly inside the Pydantic model by setting model_config:

from pydantic import BaseModel

class Item(BaseModel):
    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Laptop",
                    "description": "A powerful laptop",
                    "price": 999.99,
                    "tax": 89.99,
                }
            ]
        }
    }

    name: str
    description: str | None = None
    price: float
    tax: float | None = None

The dictionary inside json_schema_extra is merged into the JSON Schema that FastAPI generates for the model. Swagger UI reads the examples key and pre-fills the request body editor.


2. Field() with examples parameter

If you want per-field examples rather than a whole-model example, use the examples keyword on Field():

from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(examples=["Laptop", "Smartphone"])
    description: str | None = Field(
        default=None,
        examples=["A powerful laptop", "Latest model smartphone"]
    )
    price: float = Field(examples=[999.99, 499.99])
    tax: float | None = Field(default=None, examples=[89.99, 44.99])

Each field's examples list appears in the JSON Schema under that field's definition. This is useful when you want to document the range of acceptable values for individual fields.


3. Body() with openapi_examples

For the most control you can declare multiple named examples at the endpoint level using the openapi_examples parameter of Body():

from fastapi import FastAPI, Body
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

@app.post("/items/")
def create_item(
    item: Item = Body(
        openapi_examples={
            "laptop": {
                "summary": "A laptop example",
                "description": "A complete item with all fields filled in.",
                "value": {
                    "name": "Laptop",
                    "description": "A powerful laptop",
                    "price": 999.99,
                    "tax": 89.99,
                },
            },
            "smartphone": {
                "summary": "A smartphone example",
                "description": "An item with only the required fields.",
                "value": {
                    "name": "Smartphone",
                    "price": 499.99,
                },
            },
        },
    ),
):
    return item.model_dump()

Swagger UI renders a dropdown so users can switch between the named examples. Each example can have its own summary, description, and value. This approach follows the OpenAPI 3.1 specification for request body examples.


Combining Approaches

You can mix and match these techniques. For instance, keep a model_config example on the model for general-purpose documentation, and add openapi_examples on specific endpoints where you need scenario-based examples (e.g. "valid item", "minimal item", "edge-case item").

💡 Best Practices

  • Use realistic data. Avoid placeholder strings like "string" or numbers like 0. Real-looking data helps consumers understand the domain instantly.

  • Cover edge cases. Provide examples that show optional fields omitted, minimum/maximum values, and special formats. This helps API consumers handle all scenarios.

  • Keep examples up to date. When you add or rename a field, update your examples too. Stale examples cause more confusion than no examples at all.

  • Prefer model_config for simple cases. If your model is used in only one endpoint and you need a single example, json_schema_extra is the simplest option.

  • Use openapi_examples for complex endpoints. When an endpoint accepts different kinds of payloads (e.g. creating different product types), multiple named examples communicate the intent clearly.

  • Include summary and description in named examples. These fields appear in the Swagger UI dropdown and help users pick the right example without expanding each one.

  • Do not duplicate validation logic in examples. Examples are for documentation only; they do not affect runtime validation. Rely on Field() constraints for actual enforcement.

🔗 What's Next?

In the next lesson you will explore Global Dependencies, where you will learn how to apply dependency injection at the application level so that every endpoint shares common logic like authentication checks or database sessions.

📖 Additional Resources

💡 Hint

Use model_config = {'json_schema_extra': {'examples': [...]}} in your Pydantic model, or pass openapi_examples to Body().

Ready to Practice?

Now that you understand the theory, let's put it into practice with hands-on coding!

Start Interactive Lesson