smithy-lang / smithy

Smithy is a protocol-agnostic interface definition language and set of tools for generating clients, servers, and documentation for any programming language.

Home Page:https://smithy.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add support for untagged union types

Xtansia opened this issue · 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.

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.

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

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.

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.

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