Pydantic
Python vs. JavaScript (Objects & JSON)
| Concept | Python 🐍 | JavaScript 📜 | The Bridge (JSON) |
|---|---|---|---|
| Simple Key-Value Data | Dictionary (dict) my_dict = {"name": "Ashok", "age": 30} | Object const myObj = {name: "Ashok", age: 30} | JSON (JavaScript Object Notation) is a text format that looks like a JS object. It's a universal language for sending data between systems. |
| Complex Blueprints | Class A blueprint for creating objects with specific attributes (data) and methods (functions). | Class A modern way (syntactic sugar) to create object blueprints. | You can't send a "class" or a "function" in JSON. You only send the data from an object instance. |
The Core Idea: You can't send a "Python object" to a "JavaScript frontend" or store it directly in a database like Redis. You must first serialize it—convert it into a universal string format. That format is JSON.
- In Python:
json.dumps(my_dict)-> turns a dictionary into a JSON string. - In JavaScript:
JSON.stringify(myObj)-> turns an object into a JSON string.
The Pydantic Lifecycle
Pydantic's job is to be the strict, intelligent gatekeeper between the messy world of raw JSON strings and your clean, predictable Python objects.
Here is the flow of data:
Raw JSON String < - > Python Dictionary < - > Pydantic Model Instance
Let's look at the tools for moving between these states:
1. res.json() (from httpx or requests)
- What it does: Takes the raw text response from an API and parses it into a standard Python
dictorlist. - Analogy: It's like opening an envelope and taking out the letter. The letter is now a Python dictionary, but you haven't actually read or understood it yet.
- Starts with: Raw API response.
- Ends with: Python
dict.
2. YourModel.model_validate(python_dict)
- What it does: This is the main validation step. It takes a Python
dictand creates a true instance of your Pydantic model. It checks that all required fields are present, converts types (e.g., a date string like"2025-07-27T04:32:58Z"becomes a Pythondatetimeobject), and runs any custom validators you've defined. - Analogy: You are now reading the letter, checking that it's addressed to you, that the date makes sense, and that the signature is valid.
- Starts with: Python
dict. - Ends with: A Pydantic model instance (a smart Python object).
3. pydantic_instance.model_dump()
- What it does: The reverse of
model_validate. It takes your Pydantic model instance and converts it back into a simple Pythondict. - Analogy: You are writing a simple summary of the letter in your notebook.
- Starts with: Pydantic model instance.
- Ends with: Python
dict.
4. pydantic_instance.model_dump_json()
- What it does: Does
model_dump()and thenjson.dumps()on the result. It gives you a clean JSON string directly from your Pydantic instance, ready to be sent over the network or stored. It intelligently handles complex types likedatetime. - Analogy: You are typing up the letter's contents into an email to forward it.
- Starts with: Pydantic model instance.
- Ends with: A JSON-formatted string.
5. YourModel.model_validate_json(json_string)
- What it does: The reverse of
model_dump_json. It takes a raw JSON string, parses it into a dictionary, and then validates that dictionary into a Pydantic model instance, all in one step. - Analogy: You receive an email, open it, and immediately understand its contents and verify its authenticity, all in one motion.
- Starts with: A JSON-formatted string.
- Ends with: A Pydantic model instance.
How to Store Data in Redis
Redis stores strings, which are sequences of bytes.
You cannot give Redis a Python object directly. You must serialize it into a string first.
The Correct Workflow for Caching:
- Fetch & Validate: Get data from the API and validate it into a Pydantic instance.
pydantic_instance = NewsApiResponse.model_validate(res.json())
- Serialize for Storage: Convert the Pydantic instance into a JSON string.
json_string_to_store = pydantic_instance.model_dump_json()
- Store in Redis: Save that string in Redis.
await redis.set("my_key", json_string_to_store)
- Retrieve from Redis: Get the string back from the cache.
cached_json_string = await redis.get("my_key")
- Parse from Storage: Convert the JSON string from Redis back into a Pydantic instance.
pydantic_instance = NewsApiResponse.model_validate_json(cached_json_string)
Integration
By returning data as an instance of Pydantic model, you are sending is the universal language of the web: JSON.
Here’s a step-by-step breakdown of what happens when your frontend calls this API endpoint:
-
Your FastAPI Backend (
Python Land):- Your code returns
fetched_news.articles, which is alistof PydanticArticleobjects. - Because you've defined
response_model=list[Article], FastAPI does the final, magic step for you automatically. It takes your list of Pydantic objects and calls.model_dump_json()on them behind the scenes. - Your server sends a raw JSON string over the network. It looks like this:
[ { "source": {"id": null, "name": "KSBY San Luis Obispo News"}, "author": "Grace Bennett", "title": "SpaceX targets Saturday evening for launch...", "description": "SpaceX is targeting Saturday evening...", "url": "https://www.ksby.com/...", "urlToImage": "https://ewscripps.brightspotcdn.com/...", "publishedAt": "2025-07-27T04:32:58Z", "content": "Update (9:31 p.m.) - ..." }, { ... another article ... } ]
- Your code returns
-
The Frontend (
JavaScript/React Land):- Your NextJS or React app uses a function like
fetchor a library likeaxiosto callhttp://your-api-url/home. - It receives the raw JSON string from your server.
- You then call the
.json()method on the response object (e.g.,const data = await response.json();). - This JavaScript method parses the JSON string into a native JavaScript array of objects. The
datavariable in your frontend will look like this, ready to be used in your components:[ { source: {id: null, name: "KSBY San Luis Obispo News"}, author: "Grace Bennett", title: "SpaceX targets Saturday evening for launch...", // ... and so on for all fields } // ... more article objects ]
- Your NextJS or React app uses a function like
Conclusion: You are sending exactly what the frontend expects. The Pydantic models are a server-side tool for validation and structure; by the time the data leaves your server, it's plain, universal JSON.