diff --git a/python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py b/python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py index 848bba8386eb..0ed36f209d00 100644 --- a/python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py +++ b/python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py @@ -206,6 +206,7 @@ def create_rest_api_operations( paths = parsed_document.get("paths", {}) request_objects = {} + unique_operation_ids_registered: set[str] = set() servers = parsed_document.get("servers", []) @@ -230,7 +231,15 @@ def create_rest_api_operations( for path, methods in paths.items(): for method, details in methods.items(): request_method = method.lower() - operationId = details.get("operationId", path + "_" + request_method) + # Validate that operationId exists + if "operationId" not in details: + raise PluginInitializationError(f"operationId missing, path: '{path}', method: '{method}'") + operationId = details["operationId"] + if operationId in unique_operation_ids_registered: + raise PluginInitializationError( + f"Duplicate operationId: '{operationId}', path: '{path}', method: '{method}'" + ) + unique_operation_ids_registered.add(operationId) summary = details.get("summary", None) description = details.get("description", None) diff --git a/python/tests/unit/connectors/openapi_plugin/duplicate-operationid-openapi.yaml b/python/tests/unit/connectors/openapi_plugin/duplicate-operationid-openapi.yaml new file mode 100644 index 000000000000..62162de97859 --- /dev/null +++ b/python/tests/unit/connectors/openapi_plugin/duplicate-operationid-openapi.yaml @@ -0,0 +1,32 @@ +openapi: 3.0.3 +info: + title: Simple HTTPBin API + version: 1.0.0 + +servers: + - url: https://httpbin.org + +paths: + /get: + get: + operationId: duplicateId + summary: Simple GET request to httpbin.org + responses: + '200': + description: Successful response from httpbin + content: + application/json: + schema: + type: object + + /ip: + get: + operationId: duplicateId + summary: Get client IP address from httpbin + responses: + '200': + description: Successful response with IP + content: + application/json: + schema: + type: object diff --git a/python/tests/unit/connectors/openapi_plugin/no-operationid-openapi.yaml b/python/tests/unit/connectors/openapi_plugin/no-operationid-openapi.yaml new file mode 100644 index 000000000000..f621ca7d461b --- /dev/null +++ b/python/tests/unit/connectors/openapi_plugin/no-operationid-openapi.yaml @@ -0,0 +1,17 @@ +openapi: 3.0.3 +info: + title: Simple HTTPBin API + version: 1.0.0 +servers: + - url: https://httpbin.org +paths: + /get: + get: + summary: Simple GET request to httpbin.org + responses: + '200': + description: Successful response from httpbin + content: + application/json: + schema: + type: object