-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: route53 custom error unmarshalling #961
Conversation
...ices/route53/common/src/aws/sdk/kotlin/services/route53/internal/CustomErrorUnmarshalling.kt
Outdated
Show resolved
Hide resolved
...ices/route53/common/src/aws/sdk/kotlin/services/route53/internal/CustomErrorUnmarshalling.kt
Outdated
Show resolved
Hide resolved
...route53/common/test/aws/sdk/kotlin/services/route53/internal/CustomErrorUnmarshallingTest.kt
Outdated
Show resolved
Hide resolved
...n/kotlin/aws/sdk/kotlin/codegen/customization/route53/CustomErrorUnmarshallingIntegration.kt
Outdated
Show resolved
Hide resolved
...ices/route53/common/src/aws/sdk/kotlin/services/route53/internal/CustomErrorUnmarshalling.kt
Outdated
Show resolved
Hide resolved
...ices/route53/common/src/aws/sdk/kotlin/services/route53/internal/CustomErrorUnmarshalling.kt
Outdated
Show resolved
Hide resolved
...n/kotlin/aws/sdk/kotlin/codegen/customization/route53/CustomErrorUnmarshallingIntegration.kt
Outdated
Show resolved
Hide resolved
… route53-custom-error-unmarshalling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good. A few minor points left...fix and ship!
return ErrorDetails(details.code, details.message, details.requestId) | ||
} | ||
|
||
internal object InvalidChangeBatchDeserializer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Couldn't this and basically everything else in this file be private
(except for parseCustomXmlErrorResponse
)?
// XML Error response parser from RestXMLErrorDeserializer | ||
internal interface RestXmlErrorDetails { | ||
val requestId: String? | ||
val code: String? | ||
val message: String? | ||
} | ||
|
||
// Models "ErrorResponse" type in https://awslabs.github.io/smithy/1.0/spec/aws/aws-restxml-protocol.html#operation-error-serialization | ||
internal data class XmlErrorResponse( | ||
val error: XmlError?, | ||
override val requestId: String? = error?.requestId, | ||
) : RestXmlErrorDetails { | ||
override val code: String? = error?.code | ||
override val message: String? = error?.message | ||
} | ||
|
||
// Models "Error" type in https://awslabs.github.io/smithy/1.0/spec/aws/aws-restxml-protocol.html#operation-error-serialization | ||
internal data class XmlError( | ||
override val requestId: String?, | ||
override val code: String?, | ||
override val message: String?, | ||
) : RestXmlErrorDetails |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Do we need these classes? Couldn't the deserializers return ErrorDetails?
directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the deserializers can, the other can't. I can have the one that can return ErrorDetails?
do that but I would have to leave the other data class in there for the one that can't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing that resulted in some weird errors with other parts of the code, I think I'll just leave it as is
val lines = originalValue?.split("\n") | ||
writer.write("#L\naws.sdk.kotlin.services.route53.internal.parseCustomXmlErrorResponse(payload) ?: #L", lines?.get(0) ?: "", lines?.get(1) ?: "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Solely referring to the original value with this lines list is pretty inscrutable. I suggest giving each line a clearer name so that it's easier to understand what's going on here. We can also clean up the null checking by just requiring a non-null value up front:
requireNotNull(originalValue) { "Unexpectedly empty original value" }
val (nullCheckLine, parseLine) = originalValue.split("\n", limit = 2)
writer.write("#L", nullCheckLine)
writer.write("aws.sdk.kotlin.services.route53.internal.parseCustomXmlErrorResponse(payload) ?: #L", parseLine)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! No comments outside of what Ian already had.
...sdk/kotlin/codegen/customization/route53/ChangeResourceRecordSetsUnmarshallingIntegration.kt
Outdated
Show resolved
Hide resolved
...sdk/kotlin/codegen/customization/route53/ChangeResourceRecordSetsUnmarshallingIntegration.kt
Outdated
Show resolved
Hide resolved
...common/src/aws/sdk/kotlin/services/route53/internal/ChangeResourceRecordSetsUnmarshalling.kt
Outdated
Show resolved
Hide resolved
} | ||
|
||
// XML Error response parser from RestXMLErrorDeserializer | ||
private interface RestXmlErrorDetails { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: what purpose does this serve?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was there from the copy and pasting I did and was necessary for that code to work. I modified things and it's no longer there anymore
...sdk/kotlin/codegen/customization/route53/ChangeResourceRecordSetsUnmarshallingIntegration.kt
Outdated
Show resolved
Hide resolved
} | ||
} | ||
|
||
private object InvalidChangeBatchMessageDeserializer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: This is a nested type right? Can we not just re-use the generated deserializer for this then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified things and it's not exactly the same so no
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the generated deserializer not usable as is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of this line I believe. It should be Messages
instead of Error
. But I could be wrong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now it's not a nested type it's just a list of string. Ok I have further questions now, new comments incoming.
loop@ while (true) { | ||
when (findNextFieldIndex()) { | ||
MESSAGE_DESCRIPTOR.index -> | ||
if (messages == null) messages = deserializeString() else messages += "\n" + deserializeString() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correctness: This is modeled as a list field why are we joining it to a string with \n
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see how it looks like the Messages
field here because of the variable but it's Message
which is a String. I am assuming a response that looks like this here:
<?xml version="1.0" encoding="UTF-8"?>
<InvalidChangeBatch xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
<Messages>
<Message>Tried to create resource record set duplicate.example.com. type A, but it already exists</Message>
<Message>Tried to create resource record set duplicate.example.com. type B, but it already exists</Message>
</Messages>
<RequestId>b25f48e8-84fd-11e6-80d9-574e0c4664cb</RequestId>
</InvalidChangeBatch>
Is this even right/possible?
private fun buildInvalidChangeBatchException(messages: String?): InvalidChangeBatch { | ||
messages ?: throw DeserializationException("Missing message in InvalidChangeBatch XML response") | ||
val builder = InvalidChangeBatch.Builder() | ||
builder.message = messages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correctness: Why are we setting message
to the result of parsing the list field? Also what if it populates both Message
and Messages
?
e.g.
<?xml version="1.0" encoding="UTF-8"?>
<InvalidChangeBatch xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
<Messages>
<Message>Message from list</Message>
</Messages>
<Message>Some other message</Message>
<RequestId>b25f48e8-84fd-11e6-80d9-574e0c4664cb</RequestId>
</InvalidChangeBatch>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we setting message to the result of parsing the list field? :
I'm setting the Message
value here which is a String not a String list. That variable name is pretty confusing and makes it seem like the Messages
field. I'll change it
What if it populates both Message and Messages? :
So I don't populate Messages
right now I only extract the Message
. I also asked Monday if I had to worry about seeing a Message
not inside a Messages
tag and got told that it shouldn't happen. So that's something we have to look out for as well?
… route53-custom-error-unmarshalling
SonarCloud Quality Gate failed. 0 Bugs No Coverage information Catch issues before they fail your Quality Gate with our IDE extension SonarLint |
@@ -108,6 +111,7 @@ abstract class AwsHttpBindingProtocolGenerator : HttpBindingProtocolGenerator() | |||
writer.write("val payload = response.body.#T()", RuntimeTypes.Http.readAll) | |||
.write("val wrappedResponse = response.#T(payload)", RuntimeTypes.AwsProtocolCore.withPayload) | |||
.write("") | |||
.declareSection(ProtocolErrorDeserialization) { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you don't need the empty { }
it's already the default
Issue #
Github issue #242
Description of changes
Implements route 53 custom error unmarshalling for
InvaildChangeBatchResponse
. Tests included.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.