Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tutosrive/fastapi-CRUD-MongoDB/llms.txt

Use this file to discover all available pages before exploring further.

This API uses Pydantic — the validation library built into FastAPI — to define the shape and constraints of every request body and response payload. For storage, PyMongo works directly with Python dicts, which means MongoDB documents and Pydantic model instances are two different representations of the same data. A thin schema layer of serializer functions bridges the gap: it converts the raw MongoDB dict (whose _id key holds a BSON ObjectId) into a plain Python dict whose id key is a regular string that Pydantic can serialize to JSON.

User Model

Pydantic Model

The User model is defined in app/models/user.py:
from typing import Optional
from pydantic import BaseModel

class User(BaseModel):
    id: Optional[str] = None
    name: str
    age: int
    email: str

Fields

id
Optional[str]
default:"None"
The unique identifier for the user. When creating a user, this field should be omitted — MongoDB assigns its own _id (ObjectId), and the schema serializer maps it back to a string id in the response.
name
str
required
The full name of the user. Required in every create and update request.
age
int
required
The age of the user as a whole number. Required in every create and update request.
email
str
required
The email address of the user. Stored and returned as a plain string — no uniqueness constraint is enforced at the application layer.

Schema Serializer

app/schemas/user.py provides the functions that translate raw MongoDB documents into dicts that match the User Pydantic model:
from app.models.user import User

def user_entity(item: dict) -> dict:
    return {
        'id': str(item['_id']),
        'name': item['name'],
        'age': item['age'],
        'email': item['email'],
    }

def users_entity(items: list[User]) -> list[dict]:
    return [user_entity(item) for item in items]
user_entity() takes a single MongoDB document and replaces the _id ObjectId with a plain string under the key id. users_entity() applies user_entity() to every item in a cursor or list and returns a list of clean dicts ready for FastAPI to serialize into JSON.

Task Model

Pydantic Models

Both the Task (creation) and TaskUpdate (partial update) models are defined in app/models/task.py:
from typing import Optional
from pydantic import BaseModel

from app.models.user import User

class Task(BaseModel):
    id: Optional[str] = None
    title: str
    description: str
    completed: Optional[bool] = False
    created_by: str

class TaskUpdate(BaseModel):
    id: Optional[str] = None
    title: Optional[str] = None
    description: Optional[str] = None
    completed: Optional[bool] = False
    created_by: Optional[str] = None

Task Fields

id
Optional[str]
default:"None"
The unique identifier for the task. Omit on creation; the value is populated from MongoDB’s _id by the schema serializer when the document is returned.
title
str
required
A short title or name for the task. Required when creating a new task.
description
str
required
A longer description of what the task involves. Required when creating a new task.
completed
Optional[bool]
default:"false"
Tracks whether the task has been completed. Defaults to false on creation. Update it to true via the PUT endpoint to mark the task as done.
created_by
str
required
A string identifier for the user who created the task. Required on creation. This is stored as a plain string — there is no enforced foreign key relationship to a User document (see the MongoDB Storage section below).

TaskUpdate Fields

TaskUpdate is used exclusively by the PUT /tasks/{id} endpoint. Every field is Optional so clients can send only the fields they want to change:
id
Optional[str]
default:"None"
Not used during an update — present for structural consistency with Task. The task_update_entity() serializer strips None values, so this field is excluded from the MongoDB $set payload.
title
Optional[str]
default:"None"
New title for the task. Omit to leave the current title unchanged.
description
Optional[str]
default:"None"
New description for the task. Omit to leave the current description unchanged.
completed
Optional[bool]
default:"false"
Updated completion status. Send true to mark the task complete, false to reopen it. Note that this field defaults to false (not None), so task_update_entity() will not strip it — if you omit completed from the request body, FastAPI uses the model default of false, and MongoDB’s $set will overwrite the stored value with false. To leave completed unchanged, you must explicitly pass the current value.
created_by
Optional[str]
default:"None"
Updated creator identifier. Omit to leave the current value unchanged.

Schema Serializers

app/schemas/task.py provides three functions:
def task_entity(item: dict) -> dict:
    return {
        'id': str(item['_id']),
        'title': item['title'],
        'description': item['description'],
        'completed': item['completed'],
        'created_by': item['created_by']
    }

def tasks_entity(items: list[dict]) -> list[dict]:
    return [task_entity(item) for item in items]

def task_update_entity(item: dict) -> dict:
    copy_dict = item.copy()
    for key in copy_dict.keys():
        if item[key] == None:
            del item[key]
    return item
  • task_entity() — converts a single MongoDB task document to a JSON-ready dict, mapping _idid as a string.
  • tasks_entity() — applies task_entity() to every document in a list or cursor.
  • task_update_entity() — takes the dict produced by TaskUpdate.model_dump() and removes every key whose value is None. The resulting dict is passed directly to MongoDB’s $set operator, so only non-None fields are written to MongoDB. Fields that default to None (such as title, description, and created_by) are stripped when omitted, leaving those fields untouched in the stored document. The completed field is the exception: its default is False, not None, so it is never stripped — omitting completed from the request body will cause $set to write false to the stored document. Always pass the current value of completed explicitly if you do not intend to change it.

MongoDB Storage

MongoDB stores each resource as a BSON document with an auto-generated _id field of type ObjectId. When the application calls insert_one(user) or insert_one(task), it passes the dict produced by model_dump() — which includes 'id': None from the Pydantic model. MongoDB stores that None value under the key id alongside its own _id field. The serializer functions always read from _id (not id) when constructing the response, so the None value written into the document is harmlessly ignored on reads. The two collections used by this application are:
Collection pathStores
mong_conn.local.userUser documents
mong_conn.local.taskTask documents
The created_by field on a Task document holds a plain string value — it is not a MongoDB DBRef or an ObjectId referencing the user collection. FastAPI performs no join or existence check between tasks and users. If a user document is deleted, any tasks that reference that user’s name or ID string in created_by are unaffected and continue to exist with the original string value intact.

Build docs developers (and LLMs) love