Skip to content

Commit

Permalink
feat: Allow unverified OpenAPI calls (#8562)
Browse files Browse the repository at this point in the history
* Feed through ssl_verify value to OpenAPI

* Add release note

* Update serialization methods

* Applied black formatting
  • Loading branch information
richardpaulhudson authored Nov 22, 2024
1 parent 4e6c796 commit a8eeb20
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
31 changes: 28 additions & 3 deletions haystack/components/connectors/openapi_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from copy import copy
from typing import Any, Dict, List, Optional, Union

from haystack import component, logging
from haystack import component, default_from_dict, default_to_dict, logging
from haystack.dataclasses import ChatMessage, ChatRole
from haystack.lazy_imports import LazyImport

Expand Down Expand Up @@ -69,11 +69,15 @@ class OpenAPIServiceConnector:
"""

def __init__(self):
def __init__(self, ssl_verify: Optional[Union[bool, str]] = None):
"""
Initializes the OpenAPIServiceConnector instance
:param ssl_verify: Decide if to use SSL verification to the requests or not,
in case a string is passed, will be used as the CA.
"""
openapi_imports.check()
self.ssl_verify = ssl_verify

@component.output_types(service_response=Dict[str, Any])
def run(
Expand Down Expand Up @@ -112,7 +116,7 @@ def run(
function_invocation_payloads = self._parse_message(last_message)

# instantiate the OpenAPI service for the given specification
openapi_service = OpenAPI(service_openapi_spec)
openapi_service = OpenAPI(service_openapi_spec, ssl_verify=self.ssl_verify)
self._authenticate_service(openapi_service, service_credentials)

response_messages = []
Expand All @@ -127,6 +131,27 @@ def run(

return {"service_response": response_messages}

def to_dict(self) -> Dict[str, Any]:
"""
Serializes the component to a dictionary.
:returns:
Dictionary with serialized data.
"""
return default_to_dict(self, ssl_verify=self.ssl_verify)

@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "OpenAPIServiceConnector":
"""
Deserializes the component from a dictionary.
:param data:
The dictionary to deserialize from.
:returns:
The deserialized component.
"""
return default_from_dict(cls, data)

def _parse_message(self, message: ChatMessage) -> List[Dict[str, Any]]:
"""
Parses the message to extract the method invocation descriptor.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features:
- |
When making function calls via OpenAPI, allow both switching SSL verification off and specifying a certificate authority to use for it.
10 changes: 9 additions & 1 deletion test/components/connectors/test_openapi_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_run(self, openapi_mock, test_files_path):

connector.run(messages=messages, service_openapi_spec=spec, service_credentials="fake_key")

openapi_mock.assert_called_once_with(spec)
openapi_mock.assert_called_once_with(spec, ssl_verify=None)
mock_service.authenticate.assert_called_once_with("apikey", "fake_key")

# verify call went through on the wire with the correct parameters
Expand Down Expand Up @@ -331,3 +331,11 @@ def test_run_with_body_properties_missing_in_invocation_args(self, openapi_mock,
ValueError, match="Missing requestBody parameter: 'message' required for the 'greet' operation."
):
connector.run(messages=messages, service_openapi_spec=spec)

def test_serialization(self):
for test_val in ("myvalue", True, None):
openapi_service_connector = OpenAPIServiceConnector(test_val)
serialized = openapi_service_connector.to_dict()
assert serialized["init_parameters"]["ssl_verify"] == test_val
deserialized = OpenAPIServiceConnector.from_dict(serialized)
assert deserialized.ssl_verify == test_val

0 comments on commit a8eeb20

Please sign in to comment.