Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions airflow-core/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ repos:
^src/airflow/utils/serve_logs/.*\.py$|
^tests/unit/api_fastapi/.*\.py$|
^tests/unit/utils/test_serve_logs\.py$
- id: check-openapi-exception-doc-in-sync
name: Check API routes declare the HTTP statuses they raise
entry: ../scripts/ci/prek/check_openapi_exception_doc_in_sync.py
language: python
pass_filenames: true
files: ^src/airflow/api_fastapi/.*/routes/.*\.py$
- id: create-missing-init-py-files-tests
name: Create missing init.py files in tests
entry: ../scripts/ci/prek/check_init_in_tests.py
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/NextRunAssetsResponse'
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Not Found
'422':
description: Validation Error
content:
Expand Down Expand Up @@ -403,6 +409,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/PartitionedDagRunCollectionResponse'
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Not Found
'422':
description: Validation Error
content:
Expand Down Expand Up @@ -439,6 +451,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/PartitionedDagRunDetailResponse'
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Not Found
'422':
description: Validation Error
content:
Expand Down Expand Up @@ -2130,6 +2148,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/TeamCollectionResponse'
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Forbidden
'422':
description: Validation Error
content:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1991,6 +1991,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
'422':
description: Validation Error
content:
Expand Down Expand Up @@ -9878,6 +9884,12 @@ paths:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Forbidden
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPExceptionResponse'
description: Not Found
'409':
content:
application/json:
Expand Down Expand Up @@ -10026,6 +10038,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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,11 @@ def patch_connection(
return connection


@connections_router.post("/test", dependencies=[Depends(requires_access_connection(method="POST"))])
@connections_router.post(
"/test",
responses=create_openapi_http_exception_doc([status.HTTP_400_BAD_REQUEST]),
dependencies=[Depends(requires_access_connection(method="POST"))],
)
def test_connection(
test_body: ConnectionBody,
user: GetUserDep,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def _buffered_ndjson_stream(
@task_instances_log_router.get(
"/{task_id}/logs/{try_number}",
responses={
**create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND]),
**create_openapi_http_exception_doc([status.HTTP_400_BAD_REQUEST, status.HTTP_404_NOT_FOUND]),
status.HTTP_200_OK: {
"description": "Successful Response",
"content": ndjson_example_response_for_get_log,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def patch_variable(
@variables_router.post(
"",
status_code=status.HTTP_201_CREATED,
responses=create_openapi_http_exception_doc([status.HTTP_409_CONFLICT]),
responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND, status.HTTP_409_CONFLICT]),
dependencies=[Depends(action_logging()), Depends(requires_access_variable("POST"))],
)
def post_variable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
NextRunAssetEventResponse,
NextRunAssetsResponse,
)
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.core_api.routes.public.assets import OnlyActiveFilter
from airflow.api_fastapi.core_api.security import (
requires_access_asset,
Expand Down Expand Up @@ -142,6 +143,7 @@ def get_assets(

@assets_router.get(
"/next_run_assets/{dag_id}",
responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND]),
dependencies=[Depends(requires_access_asset(method="GET")), Depends(requires_access_dag(method="GET"))],
)
def next_run_assets(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
PartitionedDagRunDetailResponse,
PartitionedDagRunResponse,
)
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.core_api.security import (
ReadableDagsFilterDep,
requires_access_asset,
Expand Down Expand Up @@ -242,6 +243,7 @@ def _build_response(row, required_count: int, received_count: int) -> Partitione

@partitioned_dag_runs_router.get(
"/partitioned_dag_runs",
responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND]),
dependencies=[Depends(requires_access_asset(method="GET"))],
)
def get_partitioned_dag_runs(
Expand Down Expand Up @@ -355,6 +357,7 @@ def get_partitioned_dag_runs(

@partitioned_dag_runs_router.get(
"/pending_partitioned_dag_run/{dag_id}",
responses=create_openapi_http_exception_doc([status.HTTP_404_NOT_FOUND]),
dependencies=[Depends(requires_access_asset(method="GET")), Depends(requires_access_dag(method="GET"))],
)
def get_pending_partitioned_dag_run(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
)
from airflow.api_fastapi.common.router import AirflowRouter
from airflow.api_fastapi.core_api.datamodels.ui.teams import TeamCollectionResponse, TeamResponse
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.core_api.security import (
ReadableTeamsFilterDep,
requires_authenticated,
Expand All @@ -41,6 +42,7 @@

@teams_router.get(
path="",
responses=create_openapi_http_exception_doc([status.HTTP_403_FORBIDDEN]),
dependencies=[Depends(requires_authenticated())],
)
def list_teams(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
QueryAssetEventPartitionKeyRegex,
)
from airflow.api_fastapi.common.types import UtcDateTime
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.execution_api.datamodels.asset import AssetResponse
from airflow.api_fastapi.execution_api.datamodels.asset_event import (
AssetEventResponse,
Expand Down Expand Up @@ -106,7 +107,12 @@ def _parse_extra_params(extra: list[str] | None) -> dict[str, str]:
return result


@router.get("/by-asset")
@router.get(
"/by-asset",
responses=create_openapi_http_exception_doc(
[(status.HTTP_400_BAD_REQUEST, "Neither name nor uri was supplied")]
),
)
def get_asset_event_by_asset_name_uri(
name: Annotated[str | None, Query(description="The name of the Asset")],
uri: Annotated[str | None, Query(description="The URI of the Asset")],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from airflow._shared.timezones import timezone
from airflow.api_fastapi.common.db.common import SessionDep
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.execution_api.datamodels.hitl import (
HITLDetailRequest,
HITLDetailResponse,
Expand Down Expand Up @@ -109,7 +110,12 @@ def _check_hitl_detail_exists(hitl_detail_model: HITLDetail | None) -> HITLDetai
return hitl_detail_model


@router.patch("/{task_instance_id}")
@router.patch(
"/{task_instance_id}",
responses=create_openapi_http_exception_doc(
[(status.HTTP_409_CONFLICT, "A response has already been received for this HITLDetail")]
),
)
def update_hitl_detail(
task_instance_id: UUID,
payload: UpdateHITLDetailPayload,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@
(status.HTTP_404_NOT_FOUND, "Task Instance not found"),
(status.HTTP_409_CONFLICT, "The TI is already in the requested state"),
(HTTP_422_UNPROCESSABLE_CONTENT, "Invalid payload for the state transition"),
(
status.HTTP_500_INTERNAL_SERVER_ERROR,
"The serialized TaskFlow arg spec for this stub task is not valid",
),
]
),
response_model_exclude_unset=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from airflow.api_fastapi.common.db.common import SessionDep
from airflow.api_fastapi.core_api.base import BaseModel
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.execution_api.datamodels.xcom import (
XComResponse,
XComSequenceIndexResponse,
Expand Down Expand Up @@ -263,6 +264,9 @@ def get_mapped_xcom_by_slice(
@router.head(
"/{dag_id}/{run_id}/{task_id}/{key:path}",
responses={
**create_openapi_http_exception_doc(
[(status.HTTP_400_BAD_REQUEST, "map_index cannot be specified in a HEAD request")]
),
status.HTTP_200_OK: {
"description": "Metadata about the number of matching XCom values",
"headers": {
Expand Down Expand Up @@ -361,6 +365,14 @@ def get_xcom(
@router.post(
"/{dag_id}/{run_id}/{task_id}/{key:path}",
status_code=status.HTTP_201_CREATED,
responses=create_openapi_http_exception_doc(
[
(
status.HTTP_400_BAD_REQUEST,
"The key is empty, the value is too large to map, or is unserializable",
)
]
),
)
def set_xcom(
dag_id: str,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ export class AssetService {
dag_id: data.dagId
},
errors: {
404: 'Not Found',
422: 'Validation Error'
}
});
Expand Down Expand Up @@ -941,6 +942,7 @@ export class ConnectionService {
body: data.requestBody,
mediaType: 'application/json',
errors: {
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
422: 'Validation Error'
Expand Down Expand Up @@ -3172,6 +3174,7 @@ export class TaskInstanceService {
token: data.token
},
errors: {
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
Expand Down Expand Up @@ -4495,6 +4498,7 @@ export class VariableService {
errors: {
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
409: 'Conflict',
422: 'Validation Error'
}
Expand Down Expand Up @@ -4765,6 +4769,7 @@ export class PartitionedDagRunService {
has_created_dag_run_id: data.hasCreatedDagRunId
},
errors: {
404: 'Not Found',
422: 'Validation Error'
}
});
Expand All @@ -4790,6 +4795,7 @@ export class PartitionedDagRunService {
partition_key: data.partitionKey
},
errors: {
404: 'Not Found',
422: 'Validation Error'
}
});
Expand Down Expand Up @@ -5261,6 +5267,7 @@ export class TeamsService {
order_by: data.orderBy
},
errors: {
403: 'Forbidden',
422: 'Validation Error'
}
});
Expand Down
Loading