docs(api): add response models for FastAPI OpenAPI documentation - #5261
Open
kunzaatko wants to merge 2 commits into
Open
docs(api): add response models for FastAPI OpenAPI documentation#5261kunzaatko wants to merge 2 commits into
kunzaatko wants to merge 2 commits into
Conversation
Introduces `mineru/cli/api_response_models.py` with nine Pydantic models that describe every JSON response shape across the FastAPI endpoints. Models are wired into routes via `response_model=` and `responses=` parameters so that `/openapi.json` and `/docs` accurately reflect success, error, and ZIP-download contracts. Handlers continue to return JSONResponse/FileResponse directly, so this change is documentation-only and does not affect runtime behaviour.
Wraps the healthy-branch dict in `JSONResponse(content=...)` so that FastAPI bypasses `response_model` validation, matching the behaviour of the unhealthy branch and keeping the docs-only response-model contract intact.
Contributor
|
All contributors have signed the CLA ✍️ ✅ |
Author
|
I have read the CLA Document and I hereby sign the CLA |
This was referenced Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The FastAPI service in
mineru/cli/fast_api.pyexposes five HTTP endpoints (POST /file_parse,POST /tasks,GET /tasks/{task_id},GET /tasks/{task_id}/result,GET /health) whose handlers return manually-builtJSONResponse/FileResponseobjects. Prior to this change, none of them declared a FastAPIresponse_model=orresponses=parameter, so the OpenAPI schema (/openapi.jsonand/docs) only advertised a generic200/202success body. The actual response shapes - the shared task status payload, the per-fileresultsmap, the per-status-code error bodies, and the ZIP-download branches - were undocumented for API consumers.This change adds Pydantic v2 response models and wires them into the route decorators so that the generated OpenAPI schema accurately reflects every response contract the service actually returns.
Reasoning
/openapi.jsoncould not infer what fields a successful/file_parseresponse contains, whatGET /tasks/{id}/resultreturns when the task is still running (202 vs 200), or which status codes each route can produce. The schema now matches the actual payloads.JSONResponse/FileResponsedirectly. FastAPI bypassesresponse_modelvalidation at runtime when a handler returns aResponsesubclass, so this is a documentation-only change. The only handler bodies touched were two that previously returned a baredict(GET /tasks/{id}success andGET /healthhealthy path) - these are now wrapped inJSONResponse(content=...)so that the docs-only contract holds uniformly (without that wrap, FastAPI would applyresponse_modelvalidation to bare-dict returns, which would be a behavioural change rather than pure documentation).model_config = ConfigDict(extra="allow"), so additive future keys do not invalidate the documented schema. Nullable task payload fields (started_at,completed_at,error) are modelled asOptional[str] = None, matching whatAsyncParseTask.to_status_payloadactually emits.Changes
mineru/cli/api_response_models.py(~200 lines): ten Pydantic v2BaseModelclasses covering every response shape:TaskStatusPayload(shared base, 10 keys), extended byTaskStatusResponse,TaskSubmissionResponse,TaskMessageResponse,FileParseResultResponseParseResultInner(the per-fileresultsvalue;md_content/middle_json/model_output/content_listasOptional[str];images: dict[str, str])TaskResultResponse(standalone -backend/version/resultsonly, for/tasks/{id}/result200 JSON)HealthResponse,UnhealthyResponse,HTTPExceptionResponsemineru/cli/fast_api.py:response_model=for the success JSON shape andresponses=for additional status codes.POST /file_parse,GET /tasks/{id}/result) additionally declareapplication/zipcontent viaresponses={200: {"content": {"application/zip": {}}, ...}}alongside the JSON schema thatresponse_modelprovides.responses=.GET /tasks/{id}200 path andGET /healthhealthy path wrapped inJSONResponse(content=...)(see Reasoning).Verification
from mineru.cli.fast_api import app; app.openapi()renders with all new schemas present and per-route response codes matching the live handler inventory:POST /file_parse→ 200, 409, 422, 503POST /tasks→ 202, 422GET /tasks/{id}→ 200, 404, 422GET /tasks/{id}/result→ 200, 202, 404, 409, 422GET /health→ 200, 503200exposes bothapplication/json(fromresponse_model) andapplication/zip(fromresponsesoverride).fastapi.testclient.TestClient:GET /healthreturns the expected 11-key JSON body;GET /tasks/{unknown_id}still returns FastAPI\u2019s default{"detail": "Task not found"}404. Runtime behaviour preserved.Design notes
HTTPExceptionResponse(withdetail: str) is defined locally rather than imported because FastAPI does not ship a reusable model for the{"detail": ...}shape. The only error schema FastAPI auto-publishes isHTTPValidationError(422), defined as a hardcoded JSON-Schema dict insidefastapi/openapi/utils.py, not an importableBaseModel. Defining our own tiny error model is the idiomatic community pattern (examples:Donkie/SpoolmanMessage, severalErrorResponsemodels in ecosystem projects).responses=is used rather than router-level responses because this file uses@app.get/@app.post(...)decorators directly rather thanAPIRouter. If the file is ever migrated toAPIRouter, the shared error models could be hoisted to a singleAPIRouter(responses=common_error_responses)declaration.Scope note
I would be happy to expand this beyond the current docs-only scope into a deeper refactor of the FastAPI application as a properly modelled interface - i.e. replacing the manually-built
JSONResponse(content=dict)/FileResponsereturns with Pydantic response objects (or plain dicts returned through a typedresponse_model) so that FastAPI enforces the contract at runtime, not just in the schema. That would catch schema drift between the handlers and the documented response models, and would let the request and response types together form a single typed API surface. I kept this PR strictly documentation-only to avoid changing runtime behaviour without discussion, but the modelled-interface refactor is a natural follow-up if it is desirable here.Implementation
This change was implemented with the assistance of an LLM coding agent. All generated code was read in full and reviewed for correctness by a human before being pushed.