From 2ed3fe7c4534ad33f58f8d3ba652c0c78d78398a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:06:53 +0000 Subject: [PATCH 1/4] Initial plan From c5bda5cc8bfd458485c2bf3ea1a523b2093ad183 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:15:59 +0000 Subject: [PATCH 2/4] Add FlexMeasures-Version and API-Version response headers Co-authored-by: Flix6x <30658763+Flix6x@users.noreply.github.com> --- flexmeasures/api/__init__.py | 9 ++++++++ flexmeasures/api/tests/test_headers.py | 31 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 flexmeasures/api/tests/test_headers.py diff --git a/flexmeasures/api/__init__.py b/flexmeasures/api/__init__.py index b9740beffe..f7afec5463 100644 --- a/flexmeasures/api/__init__.py +++ b/flexmeasures/api/__init__.py @@ -157,6 +157,15 @@ def register_at(app: Flask): flexmeasures_api, url_prefix="/api" ) # now registering the blueprint will affect all endpoints + # Add version headers to all API responses + @app.after_request + def add_version_headers(response): + if request.path.startswith("/api/"): + response.headers["FlexMeasures-Version"] = flexmeasures_version + if request.path.startswith("/api/v3_0"): + response.headers["API-Version"] = "v3_0" + return response + # Load API endpoints for internal operations from flexmeasures.api.common import register_at as ops_register_at diff --git a/flexmeasures/api/tests/test_headers.py b/flexmeasures/api/tests/test_headers.py new file mode 100644 index 0000000000..64b1afa878 --- /dev/null +++ b/flexmeasures/api/tests/test_headers.py @@ -0,0 +1,31 @@ +from flask import url_for + +from flexmeasures import __version__ as flexmeasures_version + + +def test_flexmeasures_version_header_on_api_response(client): + """All API responses should include the FlexMeasures-Version header.""" + response = client.get(url_for("flexmeasures_api_ops.get_ping")) + assert response.status_code == 200 + assert response.headers.get("FlexMeasures-Version") == flexmeasures_version + + +def test_flexmeasures_version_header_on_v3_0_response(client): + """v3_0 API responses should include the FlexMeasures-Version header.""" + response = client.get(url_for("HealthAPI:is_ready")) + assert response.status_code == 200 + assert response.headers.get("FlexMeasures-Version") == flexmeasures_version + + +def test_api_version_header_on_v3_0_response(client): + """All API responses under v3_0 should include the API-Version header.""" + response = client.get(url_for("HealthAPI:is_ready")) + assert response.status_code == 200 + assert response.headers.get("API-Version") == "v3_0" + + +def test_no_api_version_header_on_non_v3_0_response(client): + """Non-v3_0 API responses should not include the API-Version header.""" + response = client.get(url_for("flexmeasures_api_ops.get_ping")) + assert response.status_code == 200 + assert "API-Version" not in response.headers From d17f03dc55cf764ae7b9e7d0d2aa40c6faf24f36 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Fri, 13 Mar 2026 14:01:50 +0100 Subject: [PATCH 3/4] docs: changelog entry Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 0890c4d01a..4b66a6a489 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -11,6 +11,7 @@ v0.32.0 | April XX, 2026 New features ------------- * Support saving state-of-charge schedules to sensors with ``"%"`` unit, using the ``soc-max`` flex-model field as the capacity for unit conversion [see `PR #1996 `_] +* Version headers (for server and API) in API responses [see `PR #2021 `_] Infrastructure / Support ---------------------- From 391e59f320b24fd9cddb19581137cab9f34ae636 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 13:26:31 +0000 Subject: [PATCH 4/4] Add version header documentation and change log entry Co-authored-by: Flix6x <30658763+Flix6x@users.noreply.github.com> --- documentation/api/change_log.rst | 2 ++ documentation/api/introduction.rst | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/documentation/api/change_log.rst b/documentation/api/change_log.rst index 921a141107..6e00d6bdaa 100644 --- a/documentation/api/change_log.rst +++ b/documentation/api/change_log.rst @@ -8,6 +8,8 @@ API change log v3.0-30 | 2026-XX-XX """""""""""""""""""" - Added ``unit`` field to the `/sensors//schedules/` (GET) endpoint for fetching a schedule, to get the schedule in a different unit still compatible to the sensor unit. +- Added ``FlexMeasures-Version`` response header to all API responses, containing the current server version (e.g. ``FlexMeasures-Version: 0.32.0``). +- Added ``API-Version`` response header to all API responses under ``/api/v3_0``, containing the API version (e.g. ``API-Version: v3_0``). v3.0-29 | 2026-02-28 diff --git a/documentation/api/introduction.rst b/documentation/api/introduction.rst index 6a44c96469..71879da713 100644 --- a/documentation/api/introduction.rst +++ b/documentation/api/introduction.rst @@ -57,7 +57,12 @@ So this tells us which API versions exist. For instance, we know that the latest Also, we can see that a list of endpoints is available on https://flexmeasures.readthedocs.io for each of these versions. -.. note:: Sunset API versions are still documented there, simply select an older version. +All API responses include a ``FlexMeasures-Version`` header with the current server version, and responses from versioned API endpoints (e.g. under ``/api/v3_0``) also include an ``API-Version`` header indicating the API version: + +.. code-block:: http + + FlexMeasures-Version: 0.32.0 + API-Version: v3_0 .. _api_auth: