smithy
smithy copied to clipboard
Question concerning constraint traits when applied to output shapes
Is Smithy opinionated, or is it specified, about how constraint traits should be handled when applied to output shapes?
For example, given the (somewhat contrived) example:
service ExampleService {
version: "1",
operations: [ ExampleOp ]
}
operation ExampleOp {
output: ExampleOpOutput
}
structure ExampleOpOutput {
@range(min: 1, max: 10)
exampleField: Integer
}
What is the expected behavior for server-side code that implements this specification?
- Are constraint traits for output shapes ignored? Meaning the server is free to return a value of, say, 11 for
exampleField
? - Must conforming server implementations (and code-generators that generate server code) emit code that ensures that return values also adhere to any constraints applied to them?
For context as to what prompted the question: as part of the implementation of our own Smithy code-generator I've been looking into the existing open source smithy-code generators (smithy-typescript and smithy-rs, which may or may not be authored by teams separate to yours), neither of which enforce constraint traits on output members for generated server code. I realize that this might be due to this not having been implemented yet in either of those two libraries and might be implemented in the future. My concern is that I've overlooked a piece of documentation that permits this behavior, which is why the functionality in those libraries does not exist. But as the authors/owners of the base smithy library and specification, would your general expectation be that any code-generators that emit server code can only be described as specification-conforming if constraint traits are respected for output values?
Knowing this information, if constraint traits should be respected for output shapes, then I can follow this up with separate issues/conversations with the smithy-typescript/smithy-rs maintainers.
Thanks!
It is our expectation that server implementations not fail to render a response when an output value does not meet the specified constraints.
This might seem counterintuitive, but our philosophy is that a change in server-side state should not be hidden from the caller unless absolutely necessary. Refusing to service an invalid request should always prevent server-side state changes, but refusing to send a response will not, as there's generally no reasonable route for a server implementation to unwind state changes due to a response serialization failure.
TypeScript server code generation does attach a validate method to generated types, so it is possible to check a response type for validation failures manually, but the only reasonable thing to do with those failures I've ever come up with is to log that they are present.
Excellent, thanks for the information, this was just the context I was missing which explains the behaviour. This makes sense. If you want to leave this issue open I'll submit a PR for the documentation later this week and link it to this issue which adds words to this effect in-case anyone else in the future is wondering what the behaviour should be. Thanks