smithy icon indicating copy to clipboard operation
smithy copied to clipboard

Add support for untagged union types

Open Xtansia opened this issue 1 year ago • 4 comments

While working on the Smithy specifications for OpenSearch we've come across a need to represent a field that may have more than one type. In this instance the field is int | boolean, which could be represented as a plain Document type in Smithy, but this would be too broad of a typing.

Our primary target from Smithy is OpenAPI where this could map onto a oneOf:

{
  "oneOf": [
    {"type": "integer"},
    {"type": "boolean"}
  ]
}

I understand that probably the largest challenge for adding this to the Smithy language is determining how to and implementing support for this in the various language generators. As we are only targeting OpenAPI an intermediary step of a trait that only affects OpenAPI translation may be a viable solution for now.

Xtansia avatar Feb 15 '24 22:02 Xtansia

I don't think this is something we can ever reasonably support. You've already called out the difficulty in representing this in a variety of programming languages, and that is a critical issue that can't be ignored.

The way you would achieve the same effect in Smithy is to use a Document, as you mentioned, or to use a custom trait/protocol that knows to flatten unions in serialization.

JordonPhillips avatar Feb 20 '24 15:02 JordonPhillips

You might also be interested in the Alloy library from disneystreaming supports untagged unions and integrates it with OpenAPI conversions: https://github.com/disneystreaming/alloy/blob/main/modules/core/resources/META-INF/smithy/unions.smithy#L54

mtdowling avatar Feb 20 '24 15:02 mtdowling

I don't think this is something we can ever reasonably support. You've already called out the difficulty in representing this in a variety of programming languages, and that is a critical issue that can't be ignored.

The way you would achieve the same effect in Smithy is to use a Document, as you mentioned, or to use a custom trait/protocol that knows to flatten unions in serialization.

Is there a world where this is feasible if it's limited to only simply differentiable types? e.g. int | string, int | [int], [int] | map<string, int>, but structA | structB is disallowed. Obviously still inconvenient to implement in some languages, but I feel would remove a lot of ambiguity in deserialization.

Xtansia avatar Feb 20 '24 22:02 Xtansia

You can't necessarily know what's simply differentiable or not, it's highly dependant on the protocol. You could imagine an XML protocol that does things like <float value="1.3"/> / <int value="1> and so on to remove that ambiguity, or similar for json. Ultimately whatever happens at the serialization layer is invisible to sdk and service tooling users, so while deserialization does matter it doesn't matter as much as long as it's deterministic. That's why Alloy's strategy of having an @untagged trait works - tooling users get the well-supported union types and the serialization layer is free to do what is must. They can attach validation to that trait to make sure their deserialization is deterministic, and if they want to convert to openapi they could write a plugin that handles the translation.

JordonPhillips avatar Feb 21 '24 14:02 JordonPhillips

Closing as this is something we do not plan to support in Smithy.

kstich avatar Apr 22 '24 16:04 kstich