Pydantic


Python vs. JavaScript (Objects & JSON)

ConceptPython 🐍JavaScript 📜The Bridge (JSON)
Simple Key-Value DataDictionary (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 BlueprintsClass 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 dict or list.
  • 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 dict and 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 Python datetime object), 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 Python dict.
  • 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 then json.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 like datetime.
  • 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:

  1. Fetch & Validate: Get data from the API and validate it into a Pydantic instance.
    • pydantic_instance = NewsApiResponse.model_validate(res.json())
  2. Serialize for Storage: Convert the Pydantic instance into a JSON string.
    • json_string_to_store = pydantic_instance.model_dump_json()
  3. Store in Redis: Save that string in Redis.
    • await redis.set("my_key", json_string_to_store)
  4. Retrieve from Redis: Get the string back from the cache.
    • cached_json_string = await redis.get("my_key")
  5. 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:

  1. Your FastAPI Backend (Python Land):

    • Your code returns fetched_news.articles, which is a list of Pydantic Article objects.
    • 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 ... }
      ]
  2. The Frontend (JavaScript/React Land):

    • Your NextJS or React app uses a function like fetch or a library like axios to call http://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 data variable 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
      ]

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.