Skip to content

Commit 17a21af

Browse files
authored
Merge pull request #84 from jhulndev/fix/pydantic-json-schema
fix(pydantic): fix pydantic JSON schema generation for FastAPI/OpenAPI
2 parents 92d900e + f97bc29 commit 17a21af

2 files changed

Lines changed: 56 additions & 3 deletions

File tree

tests/integrations/test_pydantic.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from typing import Literal
2+
23
import pytest
34
from pydantic import BaseModel, ValidationError
45

5-
from typeid.integrations.pydantic import TypeIDField
66
from typeid import TypeID
7-
7+
from typeid.integrations.pydantic import TypeIDField
88

99
USER_TYPEID_STR = str(TypeID("user"))
1010
ORDER_TYPEID_STR = str(TypeID("order"))
@@ -34,3 +34,53 @@ def test_json_serializes_as_string():
3434
m = M(id=USER_TYPEID_STR)
3535
data = m.model_dump_json()
3636
assert '"id":"' in data
37+
38+
39+
def test_json_schema_generation():
40+
"""Test that model_json_schema() works and produces correct schema."""
41+
schema = M.model_json_schema()
42+
43+
# Verify the schema structure exists
44+
assert "properties" in schema
45+
assert "id" in schema["properties"]
46+
47+
id_schema = schema["properties"]["id"]
48+
49+
# Verify it matches the documented expectations
50+
assert id_schema["type"] == "string"
51+
assert id_schema["format"] == "typeid"
52+
assert "user" in id_schema.get("description", "")
53+
assert "examples" in id_schema
54+
55+
56+
def test_json_schema_with_generate_definitions():
57+
"""
58+
Test that TypeIDField works with Pydantic's generate_definitions().
59+
60+
This mimics how FastAPI generates OpenAPI schemas and would catch
61+
the bug where __get_pydantic_json_schema__ was passing the wrong
62+
schema to the handler, causing FastAPI's OpenAPI generation to fail.
63+
"""
64+
from pydantic.json_schema import GenerateJsonSchema
65+
66+
# Use the same method FastAPI uses internally
67+
generator = GenerateJsonSchema()
68+
_, definitions = generator.generate_definitions(
69+
inputs=[(M, "validation", M.__pydantic_core_schema__)],
70+
)
71+
72+
# Verify M is in definitions
73+
assert "M" in definitions
74+
75+
# Check the id field schema
76+
m_schema = definitions["M"]
77+
assert "properties" in m_schema
78+
assert "id" in m_schema["properties"]
79+
80+
id_schema = m_schema["properties"]["id"]
81+
82+
# Verify TypeID-specific schema properties (same as test_json_schema_generation)
83+
assert id_schema["type"] == "string"
84+
assert id_schema["format"] == "typeid"
85+
assert "user" in id_schema.get("description", "")
86+
assert "examples" in id_schema

typeid/integrations/pydantic/v2.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> core_sc
6565
# Using a plain validator keeps it simple and fast.
6666
return core_schema.no_info_plain_validator_function(
6767
cls._validate,
68+
json_schema_input_schema=core_schema.str_schema(),
6869
serialization=core_schema.plain_serializer_function_ser_schema(
6970
lambda v: str(v),
7071
when_used="json",
@@ -73,7 +74,9 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> core_sc
7374

7475
@classmethod
7576
def __get_pydantic_json_schema__(cls, core_schema_: core_schema.CoreSchema, handler: Any) -> JsonSchemaValue:
76-
schema = handler(core_schema_)
77+
# Pass the json_schema_input_schema to the handler instead of the validator function schema
78+
# This allows Pydantic to generate a proper JSON schema from the string type
79+
schema = handler(core_schema_.get("json_schema_input_schema", core_schema_))
7780

7881
# Ensure JSON schema is "string"
7982
schema.update(

0 commit comments

Comments
 (0)