diff --git a/poetry.lock b/poetry.lock index 97275b8..ff0ced1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -367,7 +367,18 @@ secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17. socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "xmltodict" +version = "0.13.0" +description = "Makes working with XML feel like you are working with JSON" +optional = false +python-versions = ">=3.4" +files = [ + {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, + {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, +] + [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "8c6425b085e3770b1f16ab27d7a59d79d841040dc3125f2be8eece93d6ffd25a" +content-hash = "848238ed8d774980d2599d6865197ba62b5e05f66073815fe00671bdde3a43be" diff --git a/pyproject.toml b/pyproject.toml index b33df39..05a76c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ python = "^3.9" requests = "^2.28.2" spiffworkflow-connector-command = {git = "https://github.com/sartography/spiffworkflow-connector-command.git", rev = "main"} # spiffworkflow-connector-command = {develop = true, path = "../spiffworkflow-connector-command"} +xmltodict = "^0.13.0" diff --git a/src/connector_http/commands/get_request_v2.py b/src/connector_http/commands/get_request_v2.py index 12fe92b..436e65a 100644 --- a/src/connector_http/commands/get_request_v2.py +++ b/src/connector_http/commands/get_request_v2.py @@ -16,7 +16,10 @@ def __init__(self, basic_auth_password: str | None = None, attempts: int | None = None, ): - HttpRequestBase.__init__(self, url=url, headers=headers, basic_auth_username=basic_auth_username, basic_auth_password=basic_auth_password) + HttpRequestBase.__init__(self, url=url, + headers=headers, + basic_auth_username=basic_auth_username, + basic_auth_password=basic_auth_password) self.params = params or {} diff --git a/src/connector_http/http_request_base.py b/src/connector_http/http_request_base.py index 750b7f7..ed86048 100644 --- a/src/connector_http/http_request_base.py +++ b/src/connector_http/http_request_base.py @@ -3,6 +3,7 @@ from collections.abc import Callable import requests # type: ignore +import xmltodict from spiffworkflow_connector_command.command_interface import CommandErrorDict from spiffworkflow_connector_command.command_interface import CommandResponseDict from spiffworkflow_connector_command.command_interface import ConnectorProxyResponseDict @@ -103,19 +104,25 @@ def log(msg: str) -> None: if http_response is not None: command_response = {"raw_response": http_response.text} + content_type = http_response.headers.get("Content-Type", "") # this string can include modifiers like UTF-8, which is why it's not using == - if "application/json" in http_response.headers.get("Content-Type", ""): + if "application/json" in content_type: try: command_response = json.loads(http_response.text) except Exception as e: error = self._create_error_from_exception(exception=e, http_response=http_response) + elif "application/xml" in content_type or "text/xml" in content_type: + try: + command_response = xmltodict.parse(http_response.text) + except Exception as e: + error = self._create_error_from_exception(exception=e, http_response=http_response) log("Did parse http_response") if status >= 400 and error is None: error = self._create_error(error_code=f"HttpError{status}", http_response=http_response) return_response: CommandResponseDict = { - "body": json.dumps(command_response), + "body": command_response, "mimetype": mimetype, "http_status": status, } diff --git a/tests/connector_http/unit/test_delete_request_v2.py b/tests/connector_http/unit/test_delete_request_v2.py index 39a1339..1acc58c 100644 --- a/tests/connector_http/unit/test_delete_request_v2.py +++ b/tests/connector_http/unit/test_delete_request_v2.py @@ -16,7 +16,7 @@ def test_delete_html_from_url(self) -> None: response = request.execute(None, {}) assert mock_request.call_count == 1 - assert response["command_response"]["body"] == json.dumps({"raw_response": return_html}) + assert response["command_response"]["body"] == {"raw_response": return_html} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -35,7 +35,7 @@ def test_delete_json_from_url(self) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -53,7 +53,7 @@ def test_delete_can_handle_500(self, sleepless: Any) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 500 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is not None diff --git a/tests/connector_http/unit/test_get_request_v2.py b/tests/connector_http/unit/test_get_request_v2.py index cf96500..99528fd 100644 --- a/tests/connector_http/unit/test_get_request_v2.py +++ b/tests/connector_http/unit/test_get_request_v2.py @@ -16,7 +16,7 @@ def test_get_html_from_url(self) -> None: response = request.execute(None, {}) assert response is not None - assert response["command_response"]["body"] == json.dumps({"raw_response": return_html}) + assert response["command_response"]["body"] == {"raw_response": return_html} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -34,7 +34,43 @@ def test_get_json_from_url(self) -> None: response = request.execute(None, {}) assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json + assert response["command_response"]["http_status"] == 200 + assert response["command_response"]["mimetype"] == "application/json" + assert response["error"] is None + assert response["spiff__logs"] is not None + assert len(response["spiff__logs"]) > 0 + + def test_get_application_xml_from_url(self) -> None: + request = GetRequestV2(url="http://example.com") + return_xml = "we_return" + with patch("requests.get") as mock_request: + mock_request.return_value.status_code = 200 + mock_request.return_value.ok = True + mock_request.return_value.headers = {"Content-Type": "application/xml"} + mock_request.return_value.text = return_xml + response = request.execute(None, {}) + + assert response is not None + assert response["command_response"]["body"] == {"hey": "we_return"} + assert response["command_response"]["http_status"] == 200 + assert response["command_response"]["mimetype"] == "application/json" + assert response["error"] is None + assert response["spiff__logs"] is not None + assert len(response["spiff__logs"]) > 0 + + def test_get_text_xml_from_url(self) -> None: + request = GetRequestV2(url="http://example.com") + return_xml = "we_return" + with patch("requests.get") as mock_request: + mock_request.return_value.status_code = 200 + mock_request.return_value.ok = True + mock_request.return_value.headers = {"Content-Type": "text/xml"} + mock_request.return_value.text = return_xml + response = request.execute(None, {}) + + assert response is not None + assert response["command_response"]["body"] == {"hey": "we_return"} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -52,7 +88,7 @@ def test_get_can_handle_500(self, sleepless: Any) -> None: assert mock_request.call_count == 3 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 500 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is not None diff --git a/tests/connector_http/unit/test_head_request_v2.py b/tests/connector_http/unit/test_head_request_v2.py index 1be7d03..df4a45a 100644 --- a/tests/connector_http/unit/test_head_request_v2.py +++ b/tests/connector_http/unit/test_head_request_v2.py @@ -16,7 +16,7 @@ def test_head_html_from_url(self) -> None: response = request.execute(None, {}) assert response is not None - assert response["command_response"]["body"] == json.dumps({"raw_response": return_html}) + assert response["command_response"]["body"] == {"raw_response": return_html} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -34,7 +34,7 @@ def test_head_json_from_url(self) -> None: response = request.execute(None, {}) assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -52,7 +52,7 @@ def test_head_can_handle_500(self, sleepless: Any) -> None: assert mock_request.call_count == 3 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 500 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is not None diff --git a/tests/connector_http/unit/test_patch_request_v2.py b/tests/connector_http/unit/test_patch_request_v2.py index 8a429e2..95387db 100644 --- a/tests/connector_http/unit/test_patch_request_v2.py +++ b/tests/connector_http/unit/test_patch_request_v2.py @@ -16,7 +16,7 @@ def test_patch_html_from_url(self) -> None: response = request.execute(None, {}) assert mock_request.call_count == 1 - assert response["command_response"]["body"] == json.dumps({"raw_response": return_html}) + assert response["command_response"]["body"] == {"raw_response": return_html} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -35,7 +35,7 @@ def test_patch_json_from_url(self) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -53,7 +53,7 @@ def test_patch_can_handle_500(self, sleepless: Any) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 500 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is not None diff --git a/tests/connector_http/unit/test_post_request_v2.py b/tests/connector_http/unit/test_post_request_v2.py index e2826d6..1a448f5 100644 --- a/tests/connector_http/unit/test_post_request_v2.py +++ b/tests/connector_http/unit/test_post_request_v2.py @@ -16,7 +16,7 @@ def test_post_html_from_url(self) -> None: response = request.execute(None, {}) assert mock_request.call_count == 1 - assert response["command_response"]["body"] == json.dumps({"raw_response": return_html}) + assert response["command_response"]["body"] == {"raw_response": return_html} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -35,7 +35,7 @@ def test_post_json_from_url(self) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -53,7 +53,7 @@ def test_post_can_handle_500(self, sleepless: Any) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 500 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is not None diff --git a/tests/connector_http/unit/test_put_request_v2.py b/tests/connector_http/unit/test_put_request_v2.py index c66c3f4..221a0c9 100644 --- a/tests/connector_http/unit/test_put_request_v2.py +++ b/tests/connector_http/unit/test_put_request_v2.py @@ -16,7 +16,7 @@ def test_put_html_from_url(self) -> None: response = request.execute(None, {}) assert mock_request.call_count == 1 - assert response["command_response"]["body"] == json.dumps({"raw_response": return_html}) + assert response["command_response"]["body"] == {"raw_response": return_html} assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -35,7 +35,7 @@ def test_put_json_from_url(self) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 200 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is None @@ -53,7 +53,7 @@ def test_put_can_handle_500(self, sleepless: Any) -> None: assert mock_request.call_count == 1 assert response is not None - assert response["command_response"]["body"] == json.dumps(return_json) + assert response["command_response"]["body"] == return_json assert response["command_response"]["http_status"] == 500 assert response["command_response"]["mimetype"] == "application/json" assert response["error"] is not None