Skip to content

Commit

Permalink
Document how clients can monitor deprecation and sunset response head…
Browse files Browse the repository at this point in the history
…ers (#565)

* Clarify use of None values in test util

Signed-off-by: F.N. Claessen <felix@seita.nl>

* HTTP headers are allowed to contain multiple keys with the same name

Signed-off-by: F.N. Claessen <felix@seita.nl>

* Add client-side code example to API introduction, showing how to monitor the response headers for deprecation and sunset warnings

Signed-off-by: F.N. Claessen <felix@seita.nl>

* Changelog entry

Signed-off-by: F.N. Claessen <felix@seita.nl>

* Missing API changelog entries for introducing new API documentation subsections

Signed-off-by: F.N. Claessen <felix@seita.nl>

Signed-off-by: F.N. Claessen <felix@seita.nl>
  • Loading branch information
Flix6x committed Dec 29, 2022
1 parent 60e3ec3 commit 02299a5
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 16 deletions.
2 changes: 2 additions & 0 deletions documentation/api/change_log.rst
Expand Up @@ -20,6 +20,8 @@ v3.0-5 | 2022-12-30
- ``production-price-sensor`` -> send in ``flex-context`` instead
- ``inflexible-device-sensors`` -> send in ``flex-context`` instead

- Added a subsection on deprecating and sunsetting to the Introduction section.
- Added a subsection on describing flexibility to the Notation section.

v3.0-4 | 2022-12-08
"""""""""""""""""""
Expand Down
20 changes: 20 additions & 0 deletions documentation/api/introduction.rst
Expand Up @@ -119,3 +119,23 @@ More information about a deprecation, sunset, and possibly recommended replaceme
- ``"latest-version"``
- ``"alternate"``
- ``"sunset"``

Here is a client-side code example in Python (this merely prints out the deprecation header, sunset header and relevant links, and should be revised to make use of the client's monitoring tools):

.. code-block:: python
def check_deprecation_and_sunset(self, url, response):
"""Print deprecation and sunset headers, along with info links.
Reference
---------
https://flexmeasures.readthedocs.io/en/latest/api/introduction.html#deprecation-and-sunset
"""
# Go through the response headers in their given order
for header, content in response.headers:
if header == "Deprecation":
print(f"Your request to {url} returned a deprecation warning. Deprecation: {content}")
elif header == "Sunset":
print(f"Your request to {url} returned a sunset warning. Sunset: {content}")
elif header == "Link" and ('rel="deprecation";' in content or 'rel="sunset";' in content):
print(f"Further info is available: {content}")
2 changes: 1 addition & 1 deletion documentation/changelog.rst
Expand Up @@ -44,7 +44,7 @@ Infrastructure / Support
* Revised strategy for removing unchanged beliefs when saving data: retain the oldest measurement (ex-post belief), too [see `PR #518 <http://www.github.com/FlexMeasures/flexmeasures/pull/518>`_]
* Scheduling test for maximizing self-consumption, and improved time series db queries for fixed tariffs (and other long-term constants) [see `PR #532 <http://www.github.com/FlexMeasures/flexmeasures/pull/532>`_]
* Clean up table formatting for ``flexmeasures show`` CLI commands [see `PR #540 <http://www.github.com/FlexMeasures/flexmeasures/pull/540>`_]
* Add ``"Deprecation"`` and ``"Sunset"`` response headers for API users of deprecated API versions, and log warnings for FlexMeasures hosts when users still use them [see `PR #554 <http://www.github.com/FlexMeasures/flexmeasures/pull/554>`_]
* Add ``"Deprecation"`` and ``"Sunset"`` response headers for API users of deprecated API versions, and log warnings for FlexMeasures hosts when users still use them [see `PR #554 <http://www.github.com/FlexMeasures/flexmeasures/pull/554>`_ and `PR #565 <http://www.github.com/FlexMeasures/flexmeasures/pull/565>`_]
* Explain how to avoid potential ``SMTPRecipientsRefused`` errors when using FlexMeasures in combination with a mail server [see `PR #558 <http://www.github.com/FlexMeasures/flexmeasures/pull/558>`_]

.. warning:: The API endpoint (`[POST] /sensors/(id)/schedules/trigger <api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_) to make new schedules will (in v0.13) sunset the storage flexibility parameters (they move to the ``flex-model`` parameter group), as well as the parameters describing other sensors (they move to ``flex-context``).
Expand Down
11 changes: 4 additions & 7 deletions flexmeasures/api/common/utils/deprecation_utils.py
Expand Up @@ -133,22 +133,19 @@ def _add_headers(
sunset: str | None,
sunset_link: str | None,
) -> Response:
response.headers["Deprecation"] = deprecation
if sunset:
response.headers["Sunset"] = sunset
response.headers.extend({"Deprecation": deprecation})
if deprecation_link:
response = _add_link(response, deprecation_link, "deprecation")
if sunset:
response.headers.extend({"Sunset": sunset})
if sunset_link:
response = _add_link(response, sunset_link, "sunset")
return response


def _add_link(response: Response, link: str, rel: str) -> Response:
link_text = f'<{link}>; rel="{rel}"; type="text/html"'
if response.headers.get("Link"):
response.headers["Link"] += f", {link_text}"
else:
response.headers["Link"] = link_text
response.headers.extend({"Link": link_text})
return response


Expand Down
24 changes: 16 additions & 8 deletions flexmeasures/api/tests/utils.py
Expand Up @@ -114,17 +114,25 @@ def check_deprecation(
"""Check deprecation and sunset headers.
Also make sure we link to some url for further info.
If deprecation is None, make sure there are *no* deprecation headers.
If sunset is None, make sure there are *no* sunset headers.
"""
print(response.headers)
if deprecation:
assert deprecation in response.headers.get("Deprecation", [])
assert 'rel="deprecation"' in response.headers.get("Link", [])
assert deprecation in response.headers.getlist("Deprecation")
assert any(
'rel="deprecation"' in link for link in response.headers.getlist("Link")
)
else:
assert deprecation not in response.headers.get("Deprecation", [])
assert 'rel="deprecation"' not in response.headers.get("Link", [])
assert deprecation not in response.headers.getlist("Deprecation")
assert all(
'rel="deprecation"' not in link for link in response.headers.getlist("Link")
)
if sunset:
assert sunset in response.headers.get("Sunset", [])
assert 'rel="sunset"' in response.headers.get("Link", [])
assert sunset in response.headers.getlist("Sunset")
assert any('rel="sunset"' in link for link in response.headers.getlist("Link"))
else:
assert sunset not in response.headers.get("Sunset", [])
assert 'rel="sunset"' not in response.headers.get("Link", [])
assert sunset not in response.headers.getlist("Sunset")
assert all(
'rel="sunset"' not in link for link in response.headers.getlist("Link")
)

0 comments on commit 02299a5

Please sign in to comment.