Showing posts with label API. Show all posts
Showing posts with label API. Show all posts

Wednesday, 21 October 2026

FastAPI Query Parameters with Pydantic Models: Pagination, Filtering, and Search

 

Image

FastAPI Query Parameters with Pydantic Models: Pagination, Filtering, and Search

When building REST APIs with Python, handling query parameters is a common requirement. An API might need pagination to limit the number of records returned, filters to narrow down results, and search parameters to find specific items.

FastAPI makes these tasks easier with Pydantic models, Annotated, and Query().

Instead of managing multiple query parameters independently, you can group related parameters into reusable models, validate their values, and keep your API endpoints organized.

In this tutorial, we will build a FastAPI endpoint that supports pagination, tag filtering, and search using Pydantic models.

1. What You Will Learn

By the end of this tutorial, you will understand how to:

  • Create Pydantic models for query parameters.

  • Implement pagination using limit and offset.

  • Accept multiple filter values in a single request.

  • Add an optional search parameter.

  • Validate query parameters with Field().

  • Test your endpoint using FastAPI's interactive documentation.

2. Install the Required Libraries

Install FastAPI and Uvicorn:

pip install "fastapi>=0.115.0" "uvicorn[standard]"

FastAPI 0.115.0 introduced support for extracting query parameters from Pydantic models using Query().

3. Import the Required Modules

Start by importing the necessary classes.

from typing import Annotated

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()

Here is what each import does:

  • FastAPI: Creates the application.

  • Query: Declares and configures query parameters.

  • BaseModel: Defines structured data models.

  • Field: Adds default values and validation constraints.

  • Annotated: Combines a type with additional parameter metadata.

4. Create a Pagination Model

Pagination allows clients to retrieve records in smaller batches rather than requesting an entire dataset.

For example, an API might return 10 records per request by default.

Create a Pydantic model:

class Pagination(BaseModel):
    limit: int = Field(default=10, ge=1)
    offset: int = Field(default=0, ge=0)

Let's understand these fields.

ParameterDefaultValidation
limit10Must be at least 1
offset0Must be at least 0

The ge argument means "greater than or equal to."

For example, limit=5 and offset=10 requests a batch of up to five records, starting after the first ten records in a typical offset-based pagination implementation.

Important: This model validates pagination values; the actual database query must apply them.

5. Create a Filtering Model

Suppose your API stores articles tagged with topics such as Python, FastAPI, and Data Science.

You can define a model that accepts a list of tags.

class Filters(BaseModel):
    tags: list[str] = Field(default_factory=list)

Using default_factory=list creates a fresh empty list when no tags are provided.

A request can include multiple values for the same query parameter:

/items/?tags=python&tags=fastapi

FastAPI can parse these repeated query parameters into a list:

["python", "fastapi"]

This makes it convenient to filter records by multiple tags.

6. Build the FastAPI Endpoint

Now combine the pagination and filtering models with an optional search parameter.

from typing import Annotated

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class Pagination(BaseModel):
    limit: int = Field(default=10, ge=1)
    offset: int = Field(default=0, ge=0)


class Filters(BaseModel):
    tags: list[str] = Field(default_factory=list)


@app.get("/items/")
def read_items(
    pagination: Annotated[Pagination, Query()],
    filters: Annotated[Filters, Query()],
    search: str | None = None,
):
    return {
        "pagination": pagination,
        "filters": filters,
        "search": search,
    }

Let's examine the endpoint.

Pagination parameter

pagination: Annotated[Pagination, Query()]

FastAPI extracts the model's fields from the query string and validates them against the Pagination model.

Filtering parameter

filters: Annotated[Filters, Query()]

The endpoint accepts repeated tags query parameters and groups them into the Filters model.

Search parameter

search: str | None = None

The search parameter is optional. If the client does not provide it, its value is None.

This example demonstrates parameter parsing and validation. It does not yet search a database or filter a collection of actual items.

7. Test the API with an Example Request

Start your application by saving the code in main.py and running:

uvicorn main:app --reload

Open the interactive API documentation:

http://127.0.0.1:8000/docs

You can test the endpoint using this request:

GET /items/?limit=5&offset=0&tags=python&tags=fastapi&search=documentary

The query string contains:

  • limit=5: Request up to five records.

  • offset=0: Start from the beginning.

  • tags=python: Include the Python tag.

  • tags=fastapi: Include the FastAPI tag.

  • search=documentary: Provide a search term.

8. Understand the Example Response

Because our endpoint returns the parsed parameters, the response will look like this:

{
  "pagination": {
    "limit": 5,
    "offset": 0
  },
  "filters": {
    "tags": [
      "python",
      "fastapi"
    ]
  },
  "search": "documentary"
}

This confirms that FastAPI has extracted and validated the query parameters.

To build a production API, you would use these values to construct a database query or filter an existing dataset.

9. What Happens When Validation Fails?

Pydantic validates the model fields automatically.

For example, this request contains an invalid pagination value:

/items/?limit=0

Since limit must be greater than or equal to 1, FastAPI returns a validation error rather than passing the invalid value to your endpoint.

Similarly:

/items/?offset=-5

fails because offset cannot be negative.

Automatic validation helps prevent invalid inputs from silently reaching your business logic.

10. Add a Maximum Page Size

For production applications, you may want to prevent clients from requesting excessively large batches.

You can add an upper bound with le, which means "less than or equal to."

class Pagination(BaseModel):
    limit: int = Field(default=10, ge=1, le=100)
    offset: int = Field(default=0, ge=0)

Now the API accepts a limit between 1 and 100.

This is a useful safeguard when the endpoint accesses a database or processes large amounts of data.

11. Benefits of Using Pydantic Models

Why use models instead of writing every query parameter separately?

Cleaner code: Related parameters are grouped into meaningful structures.

Reusable validation: Pagination rules can be reused across endpoints.

Automatic error handling: Invalid values are rejected before your business logic runs.

Improved documentation: FastAPI generates interactive API documentation from your endpoint definitions.

Better maintainability: As your API grows, structured parameters are easier to understand and manage.

12. Important Considerations

Before using this pattern in a production application, remember:

  • Use a FastAPI version that supports query parameter models.

  • Query parameters are public inputs and should be validated.

  • Pagination models do not automatically execute database pagination.

  • Filter models do not automatically filter database records.

  • Search parameters need actual search logic.

  • Repeated query parameters, such as tags=python&tags=fastapi, are a convenient way to pass lists.

  • For very large datasets, cursor-based pagination may be more efficient than offset-based pagination.

Also, Annotated is a standard Python typing feature. It is not specific to FastAPI, but FastAPI uses it to associate parameter metadata with type declarations.

Conclusion

FastAPI and Pydantic provide a clean way to organize and validate query parameters in modern Python APIs.

By combining Annotated, Query(), BaseModel, and Field(), you can create structured endpoints that support pagination, filtering, and search with relatively little code.

The example in this tutorial demonstrates how to accept multiple tags, validate pagination values, and parse an optional search term.

Key takeaway: Use Pydantic models to structure your API inputs, validate them early, and keep your endpoint logic easy to maintain.

Continue exploring Python, FastAPI, backend development, and practical programming tutorials at CLCODING.

Website: https://whatsapp.com/channel/0029Va5BbiT9xVJXygonSX0G

Frequently Asked Questions

Can FastAPI use Pydantic models for query parameters?

Yes. With FastAPI 0.115.0 or later, you can use a Pydantic model with Annotated[Model, Query()] to extract and validate query parameters.

How do I pass multiple tags to FastAPI?

Repeat the query parameter, such as ?tags=python&tags=fastapi. FastAPI can parse the values into a list of strings.

Does pagination automatically limit database results?

No. The model validates limit and offset. Your database query must apply those values to retrieve the requested records.

What is the purpose of Field()?

Field() lets you specify defaults, validation constraints, and other field metadata in a Pydantic model.

#FastAPI #Python #Pydantic #RESTAPI #BackendDevelopment #PythonTutorial #CLCODING

Saturday, 17 October 2026

Chat with PDF using Python Flask and Google AI Studio API

 




* {
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;
    background: #f3f5fa;
    color: #182033;
    font-family: Arial, sans-serif;
}

.app {
    width: min(780px, 94%);
    margin: 40px auto;
}

.header {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 25px;
}

.logo {
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: 15px;
    background: #4f46e5;
    color: white;
    font-weight: 800;
}

h1 {
    margin: 0 0 5px;
    font-size: 25px;
}

.header p,
.upload-panel > p,
.document-info p {
    color: #727b90;
}

.upload-panel,
.chat-panel {
    background: white;
    border: 1px solid #e4e8f0;
    border-radius: 20px;
    box-shadow: 0 12px 40px #1720330b;
}

.upload-panel {
    padding: 45px 20px;
    text-align: center;
}

.upload-icon {
    display: grid;
    place-items: center;
    width: 65px;
    height: 65px;
    margin: 0 auto 18px;
    border-radius: 18px;
    background: #eef2ff;
    color: #4f46e5;
    font-size: 35px;
}

.upload-panel input[type="file"] {
    display: block;
    width: 100%;
    max-width: 400px;
    margin: 24px auto 12px;
    padding: 10px;
    border: 1px solid #dfe3ec;
    border-radius: 10px;
}

button {
    border: 0;
    border-radius: 10px;
    padding: 12px 18px;
    background: #4f46e5;
    color: white;
    font-weight: 600;
    cursor: pointer;
}

button:hover {
    background: #4338ca;
}

.document-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    border-bottom: 1px solid #e9ecf2;
}

.file-icon {
    padding: 10px;
    border-radius: 8px;
    background: #fff0f0;
    color: #dc2626;
    font-size: 12px;
    font-weight: 800;
}

.document-info {
    flex: 1;
    min-width: 0;
}

.document-info strong {
    overflow-wrap: anywhere;
}

.document-info p {
    margin: 5px 0 0;
    font-size: 12px;
}

.secondary-btn {
    background: #eef0f6;
    color: #273149;
}

.secondary-btn:hover {
    background: #dfe3ed;
}

.messages {
    display: flex;
    flex-direction: column;
    gap: 16px;
    height: 390px;
    overflow-y: auto;
    padding: 22px;
}

.message {
    max-width: 85%;
    padding: 13px 16px;
    border-radius: 15px;
    line-height: 1.6;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.message.user {
    align-self: flex-end;
    background: #4f46e5;
    color: white;
    border-bottom-right-radius: 4px;
}

.message.assistant {
    align-self: flex-start;
    background: #f0f2f8;
    color: #182033;
    border-bottom-left-radius: 4px;
}

.chat-form {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding: 15px;
    border-top: 1px solid #e9ecf2;
}

.chat-form input {
    flex: 1;
    min-width: 150px;
    padding: 14px;
    border: 1px solid #dfe3ec;
    border-radius: 11px;
    outline-color: #4f46e5;
    font-size: 14px;
}

.loading {
    width: 100%;
    color: #4f46e5;
    font-size: 14px;
}

.htmx-indicator {
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.2s ease-in;
}

.htmx-request.htmx-indicator,
.htmx-request .htmx-indicator {
    visibility: visible;
    opacity: 1;
}

.error {
    color: #dc2626;
}

.error-message {
    color: #b91c1c !important;
}

.footer {
    margin-top: 16px;
    color: #858da0;
    font-size: 12px;
    text-align: center;
}

@media (max-width: 500px) {
    .app {
        margin: 20px auto;
    }

    .upload-panel {
        padding: 30px 15px;
    }

    .messages {
        height: 55vh;
        padding: 14px;
    }

    .message {
        max-width: 95%;
    }

    .document-bar {
        flex-wrap: wrap;
    }
}



Popular Posts

Categories

100 Python Programs for Beginner (119) AI (359) Android (25) AngularJS (1) API (2) Assembly Language (2) aws (31) Azure (12) BI (10) book (1) Books (359) Bootcamp (20) C (78) C# (12) C++ (83) cloud (1) Course (97) Coursera (307) Cybersecurity (37) data (10) Data Analysis (48) Data Analytics (31) data management (16) Data Science (443) Data Strucures (21) Deep Learning (228) Django (17) Downloads (3) edx (21) Engineering (15) Euron (30) Events (9) Excel (24) Finance (13) flask (4) flutter (1) FPL (17) Gadgets (1) Generative AI (80) Git (14) Google (55) Hadoop (3) HTML Quiz (1) HTML&CSS (48) IBM (43) IoT (3) IS (25) Java (99) Leet Code (4) Machine Learning (417) Meta (24) MICHIGAN (5) microsoft (13) Nvidia (8) Pandas (16) PHP (20) Projects (36) Python (1405) Python Bug (1) Python Coding Challenge (1303) Python Library (29) Python Mathematics (24) Python Mistakes (51) Python Pattern Challenge (38) Python Quiz (685) Python Tips (115) Python Turtle (1) Questions (3) R (72) React (7) Scripting (3) security (5) Selenium Webdriver (4) Software (21) SQL (56) Udemy (24) UX Research (1) web application (11) Web development (9) web scraping (3)

Followers

Python Coding for Kids ( Free Demo for Everyone)