Use this file to discover all available pages before exploring further.
Pydantic is the most common way to author JSON Schemas in Python. You define a model class, Pydantic generates JSON Schema with model_json_schema(), and dottxt can enforce that schema through the OpenAI-compatible API.
Set model_config = ConfigDict(extra="forbid") when you want strict object schemas. Without it, the generated schema allows extra properties.Pydantic also generates a title for fields and models. Those are omitted from the examples below for readability.
Python’s enum.Enum also works. Pydantic puts the enum definition in $defs and references it:
from enum import Enumfrom pydantic import BaseModel, ConfigDictclass Color(str, Enum): red = "red" green = "green" blue = "blue"class Palette(BaseModel): model_config = ConfigDict(extra="forbid") primary: Color accent: Color
Prefer Literal when the values are only used once. Use Enum when you want to reuse the same set of values across fields or models.
Fields typed as T | None with a default of None become nullable and optional. Fields typed as T | None = Field(...) stay required but nullable. See Optional vs Null for the semantic difference.
Use list types for repeated values, then add bounds on the list or its items as needed.Use list[T] for array fields. Pydantic maps list min_length and max_length to minItems and maxItems:
Setting bounds on arrays prevents the model from generating unbounded lists. See Bounded Arrays for more.If you need constraints on each item, put them on the item type:
Use specialized Pydantic types when you want the generated schema to carry semantic format information.Use Pydantic’s built-in types when you want semantic formats in the generated schema:
from datetime import datefrom pydantic import BaseModel, ConfigDict, EmailStrclass ContactRecord(BaseModel): model_config = ConfigDict(extra="forbid") email: EmailStr signup_date: date
Prefer semantic types like EmailStr and date over plain str when you want the schema to carry format information.
Use discriminated unions when the output can take one of several object shapes.Use Literal with Field(discriminator=...) to generate tagged oneOf schemas in Pydantic:
Pydantic emits discriminator metadata in the generated schema, but the important part for dottxt is the oneOf structure and the const tag values on each branch. That is what makes the output unambiguous at generation time.See AnyOf Object Variants for the schema design side of this pattern.
Use recursive models for trees and other nested structures where items can contain more items of the same shape.Models that reference themselves produce recursive $defs:
from __future__ import annotations enables forward references so the model can reference itself. Set bounds on recursive lists so generation does not expand without limit.Keep the recursive type under a named object property rather than using the recursive node itself as the top-level response schema.
Use validators for application-side checks, but do not rely on them to shape the generated schema.Pydantic validators run at parse time, but they do not appear in the generated JSON Schema. If you need to constrain generation, express it in the type annotation or Field():
from pydantic import BaseModel, ConfigDict, field_validatorclass Invoice(BaseModel): model_config = ConfigDict(extra="forbid") amount: float currency: str @field_validator("currency") @classmethod def currency_must_be_valid(cls, v: str) -> str: if v not in ("USD", "EUR", "GBP"): raise ValueError("unsupported currency") return v
Use Pydantic when you want Python types, runtime validation, and JSON Schema generation from one model definition. Use raw JSON Schema directly when you need full control over the output shape or keywords that do not map cleanly from Pydantic types.
Set ConfigDict(extra="forbid") when you want additionalProperties: false.
Use Literal for enums rather than json_schema_extra={"enum": [...]}.
Use validators for parse-time checks, not generation-time constraints.