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 (whoseDocumentation 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.
_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
TheUser model is defined in app/models/user.py:
Fields
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.The full name of the user. Required in every create and update request.
The age of the user as a whole number. Required in every create and update request.
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:
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 theTask (creation) and TaskUpdate (partial update) models are defined in app/models/task.py:
Task Fields
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.A short title or name for the task. Required when creating a new task.
A longer description of what the task involves. Required when creating a new task.
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.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:
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.New title for the task. Omit to leave the current title unchanged.
New description for the task. Omit to leave the current description unchanged.
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.Updated creator identifier. Omit to leave the current value unchanged.
Schema Serializers
app/schemas/task.py provides three functions:
task_entity()— converts a single MongoDB task document to a JSON-ready dict, mapping_id→idas a string.tasks_entity()— appliestask_entity()to every document in a list or cursor.task_update_entity()— takes the dict produced byTaskUpdate.model_dump()and removes every key whose value isNone. The resulting dict is passed directly to MongoDB’s$setoperator, so only non-Nonefields are written to MongoDB. Fields that default toNone(such astitle,description, andcreated_by) are stripped when omitted, leaving those fields untouched in the stored document. Thecompletedfield is the exception: its default isFalse, notNone, so it is never stripped — omittingcompletedfrom the request body will cause$setto writefalseto the stored document. Always pass the current value ofcompletedexplicitly 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 path | Stores |
|---|---|
mong_conn.local.user | User documents |
mong_conn.local.task | Task 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.