7 routes42 sections324 units

Unit 4.1 · about 4 h

19 / 324

Typed interfaces, runtime validation and configuration

Every later service in this section stands on this boundary. Untyped inputs and untyped configuration turn typos into silent corruption. Typed contracts with explicit validation move those failures to the edge where they are loud.

  • explain
  • implement

You can now

  • Compare nominal and structural typing, generics with bounded TypeVars and variance, and justify where dynamic values are quarantined at the boundary.
  • Define a typed public API with protocols and generics that keeps persistence and transport types out of domain logic.
  • Build validated input models and typed settings with explicit unknown-field and precedence behavior, and diagnose one silent-corruption path.

Covers

  • Nominal and structural typing, generics and protocols
  • Runtime validation and trusted versus untrusted boundaries
  • Typed configuration, precedence, secrets and unknown fields

Study, in this order

7 steps

  1. Pydantic Models: basic usage, data conversion and extra data
    Official docs typed-service build path

    Basic model usage including Model methods and properties (model_validate, model_dump); Data conversion; Extra data (ignore, forbid, allow); Validating data, including Creating models without validation

  2. Pydantic Validators
    Official docs typed-service build path

    Field validators (after, before, plain and wrap, in the annotated and decorator patterns); Model validators; Raising validation errors

  3. Pydantic Fields: constraints and strict fields
    Official docs typed-service build path

    Field constraints; Strict fields

  4. Pydantic Strict Mode
    Official docs typed-service build path

    As a validation parameter; At the field level, including the Strict() metadata class; As a configuration value

  5. Pydantic Settings Management: names, dotenv and priority
    Official docs typed-service build path

    Usage (env_prefix, validation_alias); Environment variable names with Unknown environment variables; Parsing environment variable values; Dotenv (.env) support, including undefined dotenv keys raising under the default extra forbid; Field value priority

  6. Interfaces and Protocols
    AlgoMaster Python - interfaces, generics and data files

    Structural vs Nominal Typing; Defining a Protocol; @runtime_checkable: Adding isinstance Support; Generic Protocols; Dependency Injection Contracts

  7. Generic Types
    AlgoMaster Python - interfaces, generics and data files

    TypeVar Basics; Generic Classes with Generic[T]; Bounded TypeVars; Variance: Why list[Product] Isn't list[Item]; Putting It Together: A Generic Service Layer

Focus on

  • Protocol defines a static duck-typing boundary. Nominal inheritance is checked by name, structural compatibility by shape. Use Protocol for dependencies the domain calls but does not own.
  • Validate at the trust boundary with model_validate and model_validate_json. model_construct skips validation and is only for already-trusted data.
  • The default extra behavior ignores unknown fields, which silently drops data. Boundary models that must reject drift use extra forbid, and strict mode rejects coercions such as '3' to 3.
  • Settings precedence is init kwargs, then environment, then dotenv, then defaults. Unknown environment names are ignored, so a misspelled variable silently keeps the default, but an undefined key in the dotenv file raises under the default extra forbid.

Reproduce closed-book

Closed-book, define a Protocol plus a generic service, a boundary model with extra forbid and a StrictInt field, and settings with a prefix. Show that model_validate coerces '3' in lax mode but strict rejects it with int_type, that an extra field raises extra_forbidden, and that init beats env beats default.

Traps

  • runtime_checkable isinstance checks method presence only, not signatures. A sender with the wrong signature passes isinstance and fails later; keep static checking as the real gate.
  • parse_obj, .dict, .json and @validator still run, so old tutorials look current. In Pydantic 2.14 they are deprecated shims whose DeprecationWarning stays hidden outside __main__, and some v1 calls now fail: .json(indent=2) raises TypeError. Use model_validate, model_dump, model_dump_json and field_validator.
  • Expecting extra forbid to catch a misspelled environment variable. Unmatched environment names never reach validation (only undefined dotenv keys raise), so test precedence with a wrong-name variable and watch the default survive.

Practice

AlgoMaster Exercise: Interfaces and Protocols

Exercises 1 to 5 on the exercise page, with the lesson sections Structural vs Nominal Typing and Dependency Injection Contracts

Complete the set for recall, then add a self-built check: a strict boundary model with forbid-extra rejects extra fields and wrong types, and settings precedence init beats env beats default holds.

Self-test

  1. A field x: int receives '123' in lax mode and under strict True. What happens in each?

  2. A payload carries an extra key y. How do default and extra forbid models differ?

  3. What are the v2 replacements for parse_obj and .dict, and why do the old names matter?

  4. Init passes port 9000, env sets 8080, default is 8000. Which wins, and what if the env name is misspelled?

Completion criterion

Stop when

You define a Protocol plus generic service without transport imports, validate good, malformed and extra-field payloads with v2 calls only, and demonstrate init beats env beats default with a misspelled variable keeping the default.

Mark passed, then open 4.2 Only mark this when you can do it without notes.

Leads to

Comes after

Resources for this unit

  • Official docs typed-service build path
    Python typing, Pydantic, FastAPI and PostgreSQLprimarycourse
    Build one record service in this order: structural protocols and generics; Pydantic models, validators, strict mode, serialization and settings; FastAPI request bodies, dependencies, errors and tests; then PostgreSQL transactions and EXPLAIN. Replay valid, malformed, duplicate and previous-schema requests through CLI and HTTP.
  • AlgoMaster Python - interfaces, generics and data files
    AlgoMastersupportcourse
    Use Interfaces and Protocols plus Generic Types for structural typing, and Working with JSON plus Working with CSV for JSONL, error handling, newline and DictReader behavior. Lesson quizzes check recall; implementation is verified with your own scripts.

Also in this section

  • AlgoMaster SQL - selected route
    AlgoMasterrequiredcourse
    Study SQL Foundations, Querying Data, Joins, Subqueries and CTEs, Window Functions, DDL, DML and Views, Performance Optimization, Transactions and Concurrency, and Data Modeling. Stop when the service queries and transaction tests pass.
  • PostgreSQL transactions and EXPLAIN
    PostgreSQLrequiredreference
    Use the transaction tutorial and EXPLAIN guide to demonstrate commit, rollback, one isolation anomaly or prevented anomaly, and a measured plan improvement on the database actually used.
  • FastAPI tutorial
    FastAPIsupportimplementation
    Use Request Body, Dependencies, Handling Errors and Testing to expose the same service layer through HTTP. Keep framework models outside the domain core and preserve the same error semantics as the CLI.
  • AlgoMaster Low-Level Design - one rehearsal
    AlgoMastersupportpractice
    Use one fitting design prompt to rehearse interface contracts, dependency direction and failure ownership. Treat the review as feedback, then verify behavior with your own tests.
  • Stas' Python Cookbook - data and interfaces
    Stas Bekmansupportreference
    Use Serialization and Deserialization plus Environment and Arguments for focused implementation help. Compare JSON, JSONL, CSV and compressed data, and never use pickle for untrusted interchange.
  • SQLAlchemy 2.1 documentation - select, Session and eager loading
    SQLAlchemyreferencereference
    Use the select() tutorial for 2.x query style, Session basics for the transaction boundary and identity map, and relationship loading for lazy versus selectinload versus joinedload plus raiseload. Use select() style and Session.execute or Session.scalars only, never the legacy Query API.
  • Alembic tutorial - migration scripts and downgrading
    SQLAlchemysupportreference
    Use Create a Migration Script, Running our First and Second Migration, Getting Information and Downgrading to run a paired upgrade and downgrade round trip on a scratch database.
  • PyArrow Parquet read and write docs
    Apache Arrowsupportreference
    Use Reading and Writing Single Files plus Table from_pydict and from_pylist to convert normalized records to Parquet and test types, nulls, column projection and schema.
  • Stripe idempotent requests
    Stripesupportreference
    Use the Idempotency-Key header contract, stored-response replay, parameter-mismatch errors and POST-only scope to implement keyed replay for one endpoint.

Quick find

Search Michi

Type to search every route, section, unit, topic and resource.

Enter opens the first result Esc closes

Reference

Keyboard shortcuts

n
Continue to the first unit not passed
j / k
Next / previous unit
1 2 3
Toggle learned, practised, passed
/
Open search
?
Show this help
Esc
Close open panels