Repository: apache/airflow
File: airflow-core/src/airflow/api_fastapi/execution_api/versions/__init__.py (Python)

Code before:
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

from __future__ import annotations

from cadwyn import HeadVersion, Version, VersionBundle

from airflow.api_fastapi.execution_api.versions.v2025_04_28 import AddRenderedMapIndexField
from airflow.api_fastapi.execution_api.versions.v2025_05_20 import DowngradeUpstreamMapIndexes
from airflow.api_fastapi.execution_api.versions.v2025_08_10 import (
    AddDagRunStateFieldAndPreviousEndpoint,
    AddIncludePriorDatesToGetXComSlice,
)
from airflow.api_fastapi.execution_api.versions.v2025_09_23 import (
    AcceptNullXComSetValue,
    AddDagVersionIdField,
)

bundle = VersionBundle(
    HeadVersion(),
    Version("2025-09-23", AddDagVersionIdField, AcceptNullXComSetValue),
    Version(
        "2025-08-10",
        AddDagRunStateFieldAndPreviousEndpoint,
        AddIncludePriorDatesToGetXComSlice,
    ),
    Version("2025-05-20", DowngradeUpstreamMapIndexes),
    Version("2025-04-28", AddRenderedMapIndexField),
    Version("2025-04-11"),
)


Review comment (bug):
We are ok without the migration since technically this was a bug in FastAPI.

Code:

```py
from fastapi import FastAPI, Body
from fastapi.testclient import TestClient
from pydantic import JsonValue
from typing import Annotated


app = FastAPI()

@app.post('/echo')
async def echo(body: Annotated[JsonValue, Body()]):
    return {'received': body, 'type': str(type(body))}

client = TestClient(app)

print('1. Testing json=None (empty body):')
try:
    response = client.post('/echo', json=None)
    print('  Status:', response.status_code)
    if response.status_code == 200:
        print('  Response:', response.json())
    else:
        print('  Error:', response.text)
except Exception as e:
    print('  Exception:', e)

print()
print('2. Testing content=\"null\" (actual JSON null):')
try:
    response = client.post('/echo', content='null', headers={'Content-Type': 'application/json'})
    print('  Status:', response.status_code)
    if response.status_code == 200:
        print('  Response:', response.json())
    else:
        print('  Error:', response.text)
except Exception as e:
    print('  Exception:', e)

```

```
1. Testing json=None (empty body):
  Status: 422
  Error: {"detail":[{"type":"missing","loc":["body"],"msg":"Field required","input":null}]}

2. Testing content="null" (actual JSON null):
  Status: 422
  Error: {"detail":[{"type":"missing","loc":["body"],"msg":"Field required","input":null}]}

```

Code after:
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

from __future__ import annotations

from cadwyn import HeadVersion, Version, VersionBundle

from airflow.api_fastapi.execution_api.versions.v2025_04_28 import AddRenderedMapIndexField
from airflow.api_fastapi.execution_api.versions.v2025_05_20 import DowngradeUpstreamMapIndexes
from airflow.api_fastapi.execution_api.versions.v2025_08_10 import (
    AddDagRunStateFieldAndPreviousEndpoint,
    AddIncludePriorDatesToGetXComSlice,
)
from airflow.api_fastapi.execution_api.versions.v2025_09_23 import AddDagVersionIdField

bundle = VersionBundle(
    HeadVersion(),
    Version("2025-09-23", AddDagVersionIdField),
    Version(
        "2025-08-10",
        AddDagRunStateFieldAndPreviousEndpoint,
        AddIncludePriorDatesToGetXComSlice,
    ),
    Version("2025-05-20", DowngradeUpstreamMapIndexes),
    Version("2025-04-28", AddRenderedMapIndexField),
    Version("2025-04-11"),
)