🐛 fix: Pydantic v2/v1 models as body_schema (FastAPI migration path)

swadhinbiswas committed 2 months ago
a4cfa86
1 parent e568aae
commit a4cfa86
2 files changed
+46 -0
▼crates/justapi-py/python/justapi/_native_helper.py
+20-0
217
217
except Exception as e: # pragma: no cover - defensive
218
218
return [f"schema validation error: {e}"]
219
219
220
+ # Pydantic v2 model class: validate via model_json_schema() through the
221
+ # Rust engine (mirrors the native fast path). This makes
222
+ # `body_schema=SomePydanticModel` work for FastAPI migrants.
223
+ model_json_schema = getattr(schema_fn, "model_json_schema", None)
224
+ if callable(model_json_schema) and _rust_validate_value is not None:
225
+ try:
226
+ schema_json = json.dumps(model_json_schema())
227
+ return _rust_validate_value(schema_json, json.dumps(body_data))
228
+ except Exception as e: # pragma: no cover - defensive
229
+ return [f"schema validation error: {e}"]
230
+
231
+ # Pydantic v1 model class: validate via schema().
232
+ v1_schema = getattr(schema_fn, "schema", None)
233
+ if callable(v1_schema) and _rust_validate_value is not None:
234
+ try:
235
+ schema_json = json.dumps(v1_schema())
236
+ return _rust_validate_value(schema_json, json.dumps(body_data))
237
+ except Exception as e: # pragma: no cover - defensive
238
+ return [f"schema validation error: {e}"]
239
+
220
240
# Legacy callable schema.
221
241
result = schema_fn(body_data)
222
242
if result is None:
223
243
▼crates/justapi-py/python/justapi/test_native.py
+26-0
296
296
s.close()
297
297
except Exception:
298
298
pass
299
+
300
+
301
+def test_pydantic_model_as_body_schema():
302
+ """Pydantic v2 models work as body_schema (validated via their JSON
303
+ Schema in the Rust engine) — FastAPI-migration path (fixed 2026-08-08)."""
304
+ from pydantic import BaseModel, Field
305
+ from justapi import JustAPIApp, JustAPITestClient
306
+
307
+ class Pet(BaseModel):
308
+ name: str = Field(..., min_length=1)
309
+ species: str
310
+
311
+ app = JustAPIApp()
312
+
313
+ @app.post("/pets", body_schema=Pet)
314
+ def create(request):
315
+ body = request.json()
316
+ return {"name": body["name"], "species": body["species"]}
317
+
318
+ c = JustAPITestClient(app)
319
+ ok = c.post("/pets", b'{"name": "rex", "species": "dog"}')
320
+ empty = c.post("/pets", b'{"name": "", "species": "dog"}')
321
+ wrong = c.post("/pets", b'{"name": 123, "species": "dog"}')
322
+ assert ok["status"] == 200, ok
323
+ assert empty["status"] == 422, empty
324
+ assert wrong["status"] == 422, wrong
299
325