Day 16 · Chapter · ~12m

Unions, Generics & Dynamic Schemas

Discriminated unions, generic models, root models, and runtime schema generation.

You’re building a payment processing service. Your webhook handler receives events from Stripe: charge.succeeded, charge.failed, invoice.created, refund.issued. Each event has different fields. Your charge has an amount and currency. Your refund has a reason and status. Your invoice has items and due_date.

At first, you define one massive Pydantic model with all possible fields, most of them optional. The handler starts with if/elif chains that check the event type, then reach into the model to pull out the fields it needs. If the model doesn’t have reason, you default it. If it does, you use it. It works.

But then your product adds custom events. Marketplace transactions, subscription adjustments, fraud alerts—each with their own shape. Your model grows. Your if/elif chain grows. Your tests multiply. You start second-guessing whether a field is actually there, or if you’re just being defensive with .get() calls.

This is where most teams give up on type safety and reach for a dictionary.

But there’s an elegant pattern in Pydantic that makes this beautiful again. A way to say: "This webhook is one of these specific shapes, nothing else." A way to let the type system guide you to the right handler, every time.

You’re about to learn why.

Practice your skills

Sign up to write and run code in this lesson.

Already have an account? Sign in