Skip to content
Merged
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
2 changes: 1 addition & 1 deletion codegen/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]
junit5 = "6.1.1"
smithy = "1.71.0"
smithy = "1.72.1"
mockito = "5.23.0"
test-logger-plugin = "4.0.0"
spotbugs = "6.0.22"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "bugfix",
"description": "Fixed REST JSON modeled error resolution by matching error identifiers by shape name when wire and modeled namespaces differ. ([#742](https://github.com/smithy-lang/smithy-python/pull/742))"
}
11 changes: 11 additions & 0 deletions packages/smithy-aws-core/src/smithy_aws_core/aio/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ def content_type(self) -> str:
def error_identifier(self) -> HTTPErrorIdentifier:
return self._error_identifier

def _resolve_error_id(
self,
*,
operation: APIOperation[Any, Any],
error_id: ShapeID,
) -> ShapeID:
for error_schema in operation.error_schemas:
if error_schema.id.name == error_id.name:
return error_schema.id
return error_id

def create_event_publisher[
OperationInput: SerializeableShape,
OperationOutput: DeserializeableShape,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "enhancement",
"description": "Enabled HTTP binding protocols to resolve modeled response errors when wire identifiers do not exactly match registered shape IDs. ([#742](https://github.com/smithy-lang/smithy-python/pull/742))"
}
25 changes: 23 additions & 2 deletions packages/smithy-http/src/smithy_http/aio/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from smithy_core.prelude import DOCUMENT
from smithy_core.schemas import APIOperation
from smithy_core.serializers import SerializeableShape
from smithy_core.shapes import ShapeID
from smithy_core.traits import EndpointTrait, HTTPTrait

from ..deserializers import HTTPResponseDeserializer
Expand Down Expand Up @@ -185,15 +186,26 @@ async def _create_error(
error_id = self.error_identifier.identify(
operation=operation, response=response
)
if error_id is not None and error_id not in error_registry:
error_id = self._resolve_error_id(
operation=operation,
error_id=error_id,
)

if error_id is None and self._matches_content_type(response):
if isinstance(response_body, bytearray):
response_body = bytes(response_body)
deserializer = self.payload_codec.create_deserializer(source=response_body)
document = deserializer.read_document(schema=DOCUMENT)
document_error_id = document.discriminator
if document_error_id not in error_registry:
document_error_id = self._resolve_error_id(
operation=operation,
error_id=document_error_id,
)

if document.discriminator in error_registry:
error_id = document.discriminator
if document_error_id in error_registry:
error_id = document_error_id
if isinstance(response_body, SeekableBytesReader):
response_body.seek(0)

Expand Down Expand Up @@ -236,6 +248,15 @@ async def _create_error(
is_retry_safe=is_throttle or is_timeout or None,
)

def _resolve_error_id(
self,
*,
operation: APIOperation[Any, Any],
error_id: ShapeID,
) -> ShapeID:
"""Resolve a response discriminator to its modeled error shape ID."""
return error_id

def _matches_content_type(self, response: HTTPResponse) -> bool:
if "content-type" not in response.fields:
return False
Expand Down
Loading