Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

logger: logging.Logger = logging.getLogger(__name__)

# Keys of an OpenAPI path item that describe an operation; the others (summary, description, servers,
# parameters, $ref, x-*) apply to the path as a whole.
HTTP_METHODS: Final = frozenset({"get", "put", "post", "delete", "options", "head", "patch", "trace"})


class OpenApiParser:
"""NOTE: SK Python only supports the OpenAPI Spec >=3.0.
Expand Down Expand Up @@ -250,8 +254,11 @@ def create_rest_api_operations(
server_urls = [{"url": "/", "variables": {}, "description": ""}]

for path, methods in paths.items():
path_parameters = methods.get("parameters", [])
for method, details in methods.items():
request_method = method.lower()
if request_method not in HTTP_METHODS:
continue
# Validate that operationId exists
if "operationId" not in details:
raise PluginInitializationError(f"operationId missing, path: '{path}', method: '{method}'")
Expand Down Expand Up @@ -290,7 +297,12 @@ def create_rest_api_operations(
logger.info(f"Skipping operation {operationId} as it is excluded.")
continue

parameters = details.get("parameters", [])
# Operation level parameters override path level ones with the same name and location.
operation_parameters = details.get("parameters", [])
overridden = {(p.get("name"), p.get("in")) for p in operation_parameters}
parameters = [
p for p in path_parameters if (p.get("name"), p.get("in")) not in overridden
] + operation_parameters
parsed_params = self._parse_parameters(parameters)
request_body = self._create_rest_api_operation_payload(operationId, details.get("requestBody", None))
responses = dict(self._create_response(details.get("responses", {})))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,45 @@ def test_create_functions_propagates_enable_file_ref_resolution():
enable_file_ref_resolution=True,
enable_http_ref_resolution=False,
)


def _path_item_spec(path_item: dict) -> dict:
return {
"openapi": "3.0.1",
"info": {"title": "t", "version": "1"},
"servers": [{"url": "https://api.example.com"}],
"paths": {"/items/{id}": path_item},
}


def test_create_rest_api_operations_path_item_keys_and_shared_parameters():
id_param = {"name": "id", "in": "path", "required": True, "schema": {"type": "string"}}
spec = _path_item_spec({
"summary": "Item",
"description": "An item",
"parameters": [id_param],
"get": {"operationId": "getItem", "responses": {"200": {"description": "ok"}}},
"delete": {"operationId": "deleteItem", "responses": {"200": {"description": "ok"}}},
})

operations = OpenApiParser().create_rest_api_operations(spec)

assert set(operations) == {"getItem", "deleteItem"}
for operation in operations.values():
assert [p.name for p in operation.parameters] == ["id"]


def test_create_rest_api_operations_operation_parameter_overrides_path_parameter():
spec = _path_item_spec({
"parameters": [{"name": "id", "in": "path", "required": True, "schema": {"type": "string"}}],
"get": {
"operationId": "getItem",
"parameters": [
{"name": "id", "in": "path", "required": True, "description": "own", "schema": {"type": "integer"}}
],
"responses": {"200": {"description": "ok"}},
},
})

operation = OpenApiParser().create_rest_api_operations(spec)["getItem"]
assert [(p.name, p.type, p.description) for p in operation.parameters] == [("id", "integer", "own")]
Loading