This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 7c0b3e66d8c Document HTTP statuses that API routes raise but never
declared (#71011)
7c0b3e66d8c is described below
commit 7c0b3e66d8cec73c6fc7629cd4f17fbff3025f5a
Author: Jyun-An Chen <[email protected]>
AuthorDate: Fri Aug 14 22:57:31 2026 +0800
Document HTTP statuses that API routes raise but never declared (#71011)
Handlers raise statuses that create_openapi_http_exception_doc never
declares, so
the generated spec — and every client built from it — has no model for a
response
the API really returns.
---
.../api_fastapi/core_api/openapi/_private_ui.yaml | 12 ++++++++
.../core_api/openapi/v2-rest-api-generated.yaml | 36 ++++++++++++++++++++++
.../core_api/routes/public/backfills.py | 1 +
.../api_fastapi/core_api/routes/public/dag_run.py | 8 ++++-
.../api_fastapi/core_api/routes/public/dags.py | 1 +
.../api_fastapi/core_api/routes/public/hitl.py | 1 +
.../core_api/routes/public/task_instances.py | 8 ++++-
.../airflow/api_fastapi/core_api/routes/ui/dags.py | 7 ++++-
.../api_fastapi/core_api/routes/ui/dependencies.py | 3 +-
.../ui/openapi-gen/requests/services.gen.ts | 8 +++++
.../airflow/ui/openapi-gen/requests/types.gen.ts | 32 +++++++++++++++++++
11 files changed, 113 insertions(+), 4 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
index 57ff25b664a..5abfa412e58 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
+++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
@@ -833,6 +833,12 @@ paths:
- $ref: '#/components/schemas/DAGRunLightResponse'
- type: 'null'
title: Response Get Latest Run Info
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Bad Request
'404':
content:
application/json:
@@ -916,6 +922,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/BaseGraphResponse'
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Bad Request
'404':
content:
application/json:
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
index b3edb5986f4..69ac00b6e37 100644
---
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
+++
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
@@ -1475,6 +1475,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
'404':
description: Not Found
content:
@@ -2121,6 +2127,12 @@ paths:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Not Found
+ '409':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Conflict
'422':
description: Validation Error
content:
@@ -2765,6 +2777,12 @@ paths:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Forbidden
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Bad Request
'404':
content:
application/json:
@@ -4251,6 +4269,12 @@ paths:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Not Found
+ '409':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Conflict
'422':
content:
application/json:
@@ -9082,6 +9106,12 @@ paths:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Forbidden
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Bad Request
'404':
content:
application/json:
@@ -10445,6 +10475,12 @@ paths:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Forbidden
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HTTPExceptionResponse'
+ description: Bad Request
'404':
content:
application/json:
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/backfills.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/backfills.py
index fb960e12ac5..a814da2d943 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/backfills.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/backfills.py
@@ -346,6 +346,7 @@ def create_backfill(
path="/dry_run",
responses=create_openapi_http_exception_doc(
[
+ status.HTTP_400_BAD_REQUEST,
status.HTTP_404_NOT_FOUND,
status.HTTP_409_CONFLICT,
status.HTTP_503_SERVICE_UNAVAILABLE,
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
index b0b2b922c16..3345dff44ef 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
@@ -159,6 +159,7 @@ def get_dag_run(dag_id: str, dag_run_id: str, session:
SessionDep) -> DAGRunResp
[
status.HTTP_400_BAD_REQUEST,
status.HTTP_404_NOT_FOUND,
+ status.HTTP_409_CONFLICT,
],
),
dependencies=[
@@ -491,7 +492,12 @@ def clear_dag_run_partitions(
@dag_run_router.get(
"",
- responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND]),
+ responses=create_openapi_http_exception_doc(
+ [
+ status.HTTP_400_BAD_REQUEST,
+ status.HTTP_404_NOT_FOUND,
+ ]
+ ),
dependencies=[Depends(requires_access_dag(method="GET",
access_entity=DagAccessEntity.RUN))],
)
def get_dag_runs(
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
index 112e6c98391..df66d97d4d1 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
@@ -449,6 +449,7 @@ def unfavorite_dag(dag_id: str, session: SessionDep, user:
GetUserDep):
[
status.HTTP_400_BAD_REQUEST,
status.HTTP_404_NOT_FOUND,
+ status.HTTP_409_CONFLICT,
HTTP_422_UNPROCESSABLE_CONTENT,
]
),
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
index 301a3923dea..a77baedd9a1 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/hitl.py
@@ -136,6 +136,7 @@ def _get_task_instance_with_hitl_detail(
task_instance_hitl_path,
responses=create_openapi_http_exception_doc(
[
+ status.HTTP_400_BAD_REQUEST,
status.HTTP_403_FORBIDDEN,
status.HTTP_404_NOT_FOUND,
status.HTTP_409_CONFLICT,
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/task_instances.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/task_instances.py
index 6ccb01dd68d..2f362786ed1 100644
---
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/task_instances.py
+++
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/task_instances.py
@@ -849,7 +849,13 @@ def get_mapped_task_instance_try_details(
@task_instances_router.post(
"/clearTaskInstances",
- responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND,
status.HTTP_409_CONFLICT]),
+ responses=create_openapi_http_exception_doc(
+ [
+ status.HTTP_400_BAD_REQUEST,
+ status.HTTP_404_NOT_FOUND,
+ status.HTTP_409_CONFLICT,
+ ]
+ ),
dependencies=[
Depends(action_logging()),
Depends(requires_access_dag(method="PUT",
access_entity=DagAccessEntity.TASK_INSTANCE)),
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py
index 2700cb1e0b5..78ed45d973d 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py
@@ -321,7 +321,12 @@ def get_dag_timetable_types(
@dags_router.get(
"/{dag_id}/latest_run",
- responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND]),
+ responses=create_openapi_http_exception_doc(
+ [
+ status.HTTP_400_BAD_REQUEST,
+ status.HTTP_404_NOT_FOUND,
+ ]
+ ),
dependencies=[Depends(requires_access_dag(method="GET",
access_entity=DagAccessEntity.RUN))],
)
def get_latest_run_info(dag_id: str, session: SessionDep) ->
DAGRunLightResponse | None:
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dependencies.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dependencies.py
index 0286b0a126f..e1e44616704 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dependencies.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dependencies.py
@@ -41,6 +41,7 @@ dependencies_router = AirflowRouter(tags=["Dependencies"])
"/dependencies",
responses=create_openapi_http_exception_doc(
[
+ status.HTTP_400_BAD_REQUEST,
status.HTTP_404_NOT_FOUND,
]
),
@@ -75,6 +76,6 @@ def get_dependencies(
try:
data = extract_single_connected_component(node_id, data["nodes"],
data["edges"])
except ValueError as e:
- raise HTTPException(404, str(e))
+ raise HTTPException(status.HTTP_404_NOT_FOUND, str(e))
return BaseGraphResponse(**data)
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
index 53f5da2de09..18f475eb78d 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
@@ -675,6 +675,7 @@ export class BackfillService {
body: data.requestBody,
mediaType: 'application/json',
errors: {
+ 400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
@@ -1027,6 +1028,7 @@ export class DagRunService {
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
+ 409: 'Conflict',
422: 'Validation Error'
}
});
@@ -1212,6 +1214,7 @@ export class DagRunService {
consuming_asset_pattern: data.consumingAssetPattern
},
errors: {
+ 400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
@@ -1862,6 +1865,7 @@ export class DagService {
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
+ 409: 'Conflict',
422: 'Unprocessable Entity'
}
});
@@ -2082,6 +2086,7 @@ export class DagService {
dag_id: data.dagId
},
errors: {
+ 400: 'Bad Request',
404: 'Not Found',
422: 'Validation Error'
}
@@ -2978,6 +2983,7 @@ export class TaskInstanceService {
body: data.requestBody,
mediaType: 'application/json',
errors: {
+ 400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
@@ -3234,6 +3240,7 @@ export class TaskInstanceService {
body: data.requestBody,
mediaType: 'application/json',
errors: {
+ 400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
@@ -4809,6 +4816,7 @@ export class DependenciesService {
dependency_type: data.dependencyType
},
errors: {
+ 400: 'Bad Request',
404: 'Not Found',
422: 'Validation Error'
}
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
index 8f9c0dd3845..5afe50bcd14 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
@@ -5426,6 +5426,10 @@ export type $OpenApiTs = {
* Successful Response
*/
200: DryRunBackfillCollectionResponse;
+ /**
+ * Bad Request
+ */
+ 400: HTTPExceptionResponse;
/**
* Unauthorized
*/
@@ -5778,6 +5782,10 @@ export type $OpenApiTs = {
* Not Found
*/
404: HTTPExceptionResponse;
+ /**
+ * Conflict
+ */
+ 409: HTTPExceptionResponse;
/**
* Validation Error
*/
@@ -5843,6 +5851,10 @@ export type $OpenApiTs = {
* Successful Response
*/
200: DAGRunCollectionResponse;
+ /**
+ * Bad Request
+ */
+ 400: HTTPExceptionResponse;
/**
* Unauthorized
*/
@@ -6383,6 +6395,10 @@ export type $OpenApiTs = {
* Not Found
*/
404: HTTPExceptionResponse;
+ /**
+ * Conflict
+ */
+ 409: HTTPExceptionResponse;
/**
* Unprocessable Entity
*/
@@ -6540,6 +6556,10 @@ export type $OpenApiTs = {
* Successful Response
*/
200: DAGRunLightResponse | null;
+ /**
+ * Bad Request
+ */
+ 400: HTTPExceptionResponse;
/**
* Not Found
*/
@@ -7064,6 +7084,10 @@ export type $OpenApiTs = {
* Successful Response
*/
200: TaskInstanceCollectionResponse;
+ /**
+ * Bad Request
+ */
+ 400: HTTPExceptionResponse;
/**
* Unauthorized
*/
@@ -7281,6 +7305,10 @@ export type $OpenApiTs = {
* Successful Response
*/
200: HITLDetailResponse;
+ /**
+ * Bad Request
+ */
+ 400: HTTPExceptionResponse;
/**
* Unauthorized
*/
@@ -8529,6 +8557,10 @@ export type $OpenApiTs = {
* Successful Response
*/
200: BaseGraphResponse;
+ /**
+ * Bad Request
+ */
+ 400: HTTPExceptionResponse;
/**
* Not Found
*/