Generated Types
This page documents what type definitions in TypeSpec are generated as in emitted libraries
Models
Flattening
model Properties { name: string;}
model Foo { @flattenProperty prop: Properties;}
{ "kind": "model", "name": "Foo", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "flatten": true, "optional": false, "type": { "kind": "model", "name": "Properties", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "flatten": false, "optional": false, "type": { "kind": "string", "encode": "string" } } ] } } ]}
Python will do dynamic flattening, exposing the non-flattening syntax, and dynamically accepting the flattened access.
class Properties(_model_base.Model): name: str = rest_field() """Required."""
class Foo(_model_base.Model): properties: "_models.Properties" = rest_field() """Required."""
__flattened_items = ["properties"]
print(f.properties.name) # Non-flattened access is preferred experienceprint(f.name) # Flattened access is dynamically supported, but not documented
CSharp will generate the model with properties being flattened. During serialization/deserialization, the model will be serialized/deserialized as a non-flattened model.
public partial class Foo{ public Foo(string name) { Argument.AssertNotNull(name, nameof(name));
Name = name; }
public string Name { get; set; }}
public partial class Foo : IUtf8JsonSerializable, IJsonModel<Foo>{ void IJsonModel<Foo>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { var format = options.Format == "W" ? ((IPersistableModel<Foo>)this).GetFormatFromOptions(options) : options.Format; if (format != "J") { throw new FormatException($"The model {nameof(Foo)} does not support writing '{format}' format."); }
writer.WriteStartObject(); writer.WritePropertyName("properties"u8); writer.WriteStartObject(); writer.WritePropertyName("name"u8); writer.WriteStringValue(Name); writer.WriteEndObject(); writer.WriteEndObject(); }
internal static Foo DeserializeFoo(JsonElement element, ModelReaderWriterOptions options = null) { options ??= ModelSerializationExtensions.WireOptions;
if (element.ValueKind == JsonValueKind.Null) { return null; } string name = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("properties"u8)) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } foreach (var property0 in property.Value.EnumerateObject()) { if (property0.NameEquals("name"u8)) { name = property0.Value.GetString(); } } } } return new Foo(name); }}
// Please note that this feature is not supported right now, and the model will be generated un-flattened.// Please comment and follow work status on: https://github.com/Azure/autorest.typescript/issues/2164
In Java, @flattenProperty
have no effect on generated libraries.
@Fluentpublic final class Properties { public Properties(); public String getName(); public Properties setName(String name);}
Models with additional properties
Additional properties of any type
Recommend usage:
model Animal { name: string; kind: string; ...Record<unknown>;}
Other usages:
model Animal extends Record<unknown> { name: string; kind: string;}
model Animal is Record<unknown> { name: string; kind: string;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "any" }}
Python models are designed to support adding any additional properties.
from .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = "Jerry"animal["age"] = 5
public partial class Animal : IJsonModel<Animal> { public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }}
// RLC inputexport interface Animal extends Record<string, unknown> { name: string; kind: string;}
// RLC outputexport interface AnimalOutput extends Record<string, any> { name: string; kind: string;}
// Modular for both legacy and non legacyexport interface Animal extends Record<string, any> { name: string; kind: string;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, Object> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, Object> additionalProperties);}
Additional properties of specific type
model AnimalProperty { category: string; value: unknown;}
model Animal { name: string; kind: string; ...Record<AnimalProperty>;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "model", "name": "AnimalProperty", "properties": [ { "kind": "property", "name": "category", "serializedName": "category", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "value", "serializedName": "value", "optional": false, "type": { "kind": "any" } } ], "additionalProperties": undefined }}
Python models are designed to support adding any additional properties.
from typing import Anyfrom .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
class AnimalProperty(_model_base.Model):
category: str = rest_field() value: Any = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = AnimalProperty(category="relationship", value="Jerry")animal["age"] = AnimalProperty(category="attribute", value=5)
Due to currently there is no way to know whether a Json could be correctly mapped into the specified type in .Net
, we currently generate any non-primitive value type in additional properties property as BinaryData
.
For typespec:
model Animal { name: string; kind: string; ...Record<AnimalProperty>;}
The C#
generated code is the same as if the type is unknown
:
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }}
For typespec with additional properties of primitive types:
model Animal { name: string; kind: string; ...Record<string>;}
The C#
generated code still has the specified type in AdditionalProperties
property:
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, string> AdditionalProperties { get; }}
// RLC inputexport interface AnimalProperty { category: string; value: unknown;}export interface Animal extends Record<string, unknown> { name: string; kind: string;}
// RLC outputexport interface AnimalProperty { category: string; value: any;}export interface Animal extends Record<string, any> { name: string; kind: string;}
// Modular for legacy clientsexport interface AnimalProperty { category: string; value: any;}export interface Animal extends Record<string, any> { name: string; kind: string;}
// Modular for non-legacy clientsexport interface AnimalProperty { category: string; value: any;}export interface Animal { name: string; kind: string; additionalProperties: Record<string, AnimalProperty>;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, AnimalProperty> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, AnimalProperty> additionalProperties);}
Additional properties of union type
model Animal { name: string; kind: string; ...Record<string | int32>;}
model Animal { name: string; kind: string; ...Record<string>; ...Record<int32>;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "union", "name": "AnimalAdditionalProperty", "generatedName": true, "values": [ { "kind": "string", "encode": "string" }, { "kind": "int32" } ] }}
Python models are designed to support adding any additional properties.
from .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = "Jerry"animal["age"] = 5
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, BinaryData> AdditionalProperties { get; }}
// RLC input and outputexport interface Animal extends Record<string, string | number> { name: string; kind: string;}
// Modular for legacy and non-legacy clientsexport interface Animal extends Record<string, string | number> { name: string; kind: string;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, BinaryData> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, BinaryData> additionalProperties);}
Additional properties of nullable type
model Animal { name: string; kind: string; ...Record<string | null>;}
{ "kind": "model", "name": "Animal", "properties": [ { "kind": "property", "name": "name", "serializedName": "name", "optional": false, "type": { "kind": "string", "encode": "string" } }, { "kind": "property", "name": "kind", "serializedName": "kind", "optional": false, "type": { "kind": "string", "encode": "string" } } ], "additionalProperties": { "kind": "nullable", "valueType": { "kind": "string", "encode": "string" } }}
Python models are designed to support adding any additional properties.
from .. import _model_basefrom .._model_base import rest_field
class Animal(_model_base.Model):
name: str = rest_field() kind: str = rest_field()
animal = Animal(name="Tom", kind="Cat")animal["friend"] = "Jerry"animal["alert"] = None
public partial class Animal : IJsonModel<Animal>{ public Animal(string name, string kind);
public string Name { get; } public string Kind { get; }
public IDictionary<string, string> AdditionalProperties { get; }}
// RLC input and outputexport interface Animal extends Record<string, string | null> { name: string; kind: string;}
// Modular for legacy and non-legacy clientsexport interface Animal extends Record<string, string | null> { name: string; kind: string;}
@Fluentpublic final class Animal implements JsonSerializable<Animal> { public Animal(String name, String kind); public String getName(); public String getKind(); public Map<String, String> getAdditionalProperties(); public Animal setAdditionalProperties(Map<String, String> additionalProperties);}
Discriminator
TypeSpec uses @discriminator
decorator to add a discriminator to a model.
TypeSpec now has two ways to represent a discriminated set.
- Use model
@discriminator("kind")model Cat { kind: string;}
model Siamese extends Cat { kind: "siamese";}
model Ragdoll extends Cat { kind: "ragdoll";}
The type of the discriminator property could be an enum (extensible or fixed):
@discriminator("kind")model Cat { kind: CatKind;}
union CatKind { string, Siamese: "siamese", Ragdoll: "ragdoll",}
model Siamese extends Cat { kind: CatKind.Siamese;}
model Ragdoll extends Cat { kind: CatKind.Ragdoll;}
- Use union
@discriminator("kind")union Cat { Siamese, Ragdoll,}
model Siamese {}
model Ragdoll {}
TCGC currently only supports the discriminated set based on models, discriminated union is not supported yet.
This is a brief structure of the models in a discriminated set in the output of TCGC.
{ "models": [ { "kind": "model", "name": "Cat", "properties": [ { "kind": "property", "name": "kind", "type": { "kind": "string" }, "discriminator": true } ], "discriminatorProperty": { // the same instance of the property in the properties list here }, "discriminatedSubtype": { "siamese": { "kind": "model", "name": "Siamese", "properties": [], "discriminatorValue": "siamese" }, "ragdoll": { "kind": "model", "name": "Ragdoll", "properties": [], "discriminatorValue": "ragdoll" } } }, { // the same instance of the model Siamese as we have above in `discriminatedSubtype` property }, { // the same instance of the model Ragdoll as we have above in `discriminatedSubtype` property } ]}
from .. import _model_basefrom .._model_base import rest_discriminator, rest_field
class Cat(_model_base.Model): kind: str = rest_discriminator(name="kind")
class Siamese(Cat): kind: Literal["siamese"] = rest_discriminator(name="kind")
class Ragdoll(Cat): kind: Literal["ragdoll"] = rest_discriminator(name="kind")
In .Net generated code, the discriminator property will be generated as internal by default, but configurable to be public.
public abstract partial class Cat{ protected Cat() { }
internal string Kind { get; set; }}
public partial class Siamese : Cat{ public Siamese() : base() { Kind = "siamese"; }}
public partial class Ragdoll : Cat{ public Ragdoll() : base() { Kind = "ragdoll"; }}
// RLC input modelsexport interface Siamese extends CatParent { kind: "siamese";}
export interface Ragdoll extends CatParent { kind: "ragdoll";}
export type Cat = CatParent | Siamese | Ragdoll;
// RLC output modelsexport interface CatOutputParent { kind: string;}
export interface SiameseOutput extends CatOutputParent { kind: "siamese";}
export interface RagdollOutput extends CatOutputParent { kind: "ragdoll";}
export type CatOutput = CatOutputParent | SiameseOutput | RagdollOutput;
// Modular models/** model interface Cat */export interface Cat { kind: string;}
/** Alias for CatUnion */export type CatUnion = Siamese | Ragdoll | Cat;
/** model interface Siamese */export interface Siamese extends Cat { kind: "siamese";}/** model interface Ragdoll */export interface Ragdoll extends Cat { kind: "ragdoll";}
public class Cat implements JsonSerializable<Cat> { public Cat(); public String getKind();}
public final class Ragdoll extends Cat { public Ragdoll(); public String getKind();}
public final class Siamese extends Cat { public Siamese(); public String getKind();}
// CatClassification provides polymorphic access to related types.// Call the interface's GetCat() method to access the common type.// Use a type switch to determine the concrete type. The possible types are:// - *Cat, *Ragdoll, *Siamesetype CatClassification interface { // GetCat returns the Cat content of the underlying type. GetCat() *Cat}
type Cat struct { // REQUIRED Kind *string}
// GetCat implements the CatClassification interface for type Cat.func (c *Cat) GetCat() *Cat { return c }
type Ragdoll struct { // CONSTANT; undefinedField has constant value "ragdoll", any specified value is ignored. Kind *string}
// GetCat implements the CatClassification interface for type Ragdoll.func (e *Ragdoll) GetCat() *Cat { return &Cat{ Kind: e.Kind, }}
type Siamese struct { // CONSTANT; undefinedField has constant value "siamese", any specified value is ignored. Kind *string}
// GetCat implements the CatClassification interface for type Siamese.func (e *Siamese) GetCat() *Cat { return &Cat{ Kind: e.Kind, }}
Nullable
TypeSpec uses | null
to represent nullable types. Nullability is handled differently in languages, but emitter authors will find information
about nullability by inspecting the type of a property.
model Foo { basicNullableProperty: string | null; modelNullableProperty: Bar | null; unionNullableProperty: Bar | Baz | null; enumNullableProperty: LR | null;}
model Bar { prop: string;}
model Baz { prop: int32;}
enum LR { left, right,}
A nullable type has kind nullable
and property valueType
. The kind of the type tells you the property is nullable, while the valueType
tells you the underlying type you want to generate.
{ "kind": "model", "name": "Foo", "properties": [ { "kind": "property", "name": "basicNullableProperty", "serializedName": "basicNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "string", "encode": "string" } } }, { "kind": "property", "name": "modelNullableProperty", "serializedName": "modelNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "model", "name": "Bar", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "optional": false, "type": { "kind": "string", "encode": "string" } } ] } } }, { "kind": "property", "name": "unionNullableProperty", "serializedName": "unionNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "union", "values": [ { "kind": "model", "name": "Bar", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "optional": false, "type": { "kind": "string", "encode": "string" } } ] }, { "kind": "model", "name": "Baz", "properties": [ { "kind": "property", "name": "prop", "serializedName": "prop", "optional": false, "type": { "kind": "int32", "encode": "int32" } } ] } ] } } }, { "kind": "property", "name": "enumNullableProperty", "serializedName": "enumNullableProperty", "optional": false, "type": { "kind": "nullable", "valueType": { "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": false } } } ]}
Python treat nullable as optional. If you actually want to send the value null
to the service without the property being ignored, you can send in corehttp.serialization.NULL
. Python does not restrict you from setting any property to this value.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Bar(_model_base.Model): prop: Optional[str] = rest_field()
class Baz(_model_base.Model): prop: Optional[str] = rest_field()
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right"
class Foo(_model_base.Model): basicNullableProperty: Optional[str] = rest_field() modelNullableProperty: Optional["_models.Bar"] = rest_field() unionNullableProperty: Optional[Union["_models.Bar", "_models.Baz"]] = rest_field() enumNullableProperty: Optional["LR"] = rest_field()
TODO
TODO
TODO
Unions
Union of literals with same type
All emitters will generate their version of a closed enum.
union LR { left: "left", right: "right",}
{ "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true}
Python never generates closed enum by design. We will always permit users to pass in additional values.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right"
public enum LR{ Left, Right}
Serialization/deserialization will respect the value defined, in this case it is “left” for LR.Left
and “right” for LR.Right
respectively.
export type LR = "left" | "right";
public enum LR { LEFT("left"), RIGHT("right");}
Inline union of literals with same type
This is union defined inline at point of usage.
model Widget { horizontal: "left" | "right";}
{ "kind": "enum", "name": "WidgetHorizontals", "generatedName": true, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true}
Python generates this as a union of literals, not as enum. We also don’t generate a closed set of literals.
from typing import Literal, Union
model Widget: horizontal: Union[Literal["left"] | Literal["right"] | str]
public partial class Widget{ public WidgetHorizontal Horizontal;}public enum WidgetHorizontal{ Left, Right}
export interface Widget { horizontal: "left" | "right";}
public enum WidgetHorizontal { LEFT("left"), RIGHT("right");}
Union of basic type and literals of that type
Each language will generate their version of an open enum.
union Colors { string, red: "red", blue: "blue",}
{ "kind": "enum", "name": "Colors", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "red", "value": "red" }, { "kind": "enumvalue", "name": "blue", "value": "blue" } ], "isFixed": false, "isUnionAsEnum": true}
Python generates open enum again here.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Colors(str, Enum, metaclass=CaseInsensitiveEnumMeta): RED = "red" BLUE = "blue"
public readonly partial struct Colors : IEquatable<Colors>{ private const string RedValue = "red"; private const string BlueValue = "blue"; public static Colors Red { get; } = new Colors(RedValue); public static Colors Blue { get; } = new Colors(BlueValue);}
export type Colors = string | "red" | "blue";
public final class Colors extends ExpandableStringEnum<Colors> { public static final Colors RED = fromString("red"); public static final Colors BLUE = fromString("blue");}
Inline union of basic type and literals of that type
This is union defined inline at point of usage which include the base type as an option.
model Widget { color: "red" | "blue" | string;}
{ "kind": "enum", "name": "WidgetColors", "generatedName": true, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "red", "value": "red" }, { "kind": "enumvalue", "name": "blue", "value": "blue" } ], "isFixed": false, "isUnionAsEnum": true}
Python generates a union of literals again.
from typing import Literal, Union
model Widget: color: Union[Literal["red"] | Literal["blue"] | str]
public partial class Widget{ public WidgetColor Color;}public readonly partial struct WidgetColor : IEquatable<WidgetColor>{ private const string RedValue = "red"; private const string BlueValue = "blue"; public static WidgetColor Red { get; } = new WidgetColor(RedValue); public static WidgetColor Blue { get; } = new WidgetColor(BlueValue);}
export interface Widget { color: "red" | "blue" | string;}
public final class WidgetColor extends ExpandableStringEnum<Colors> { public static final Color RED = fromString("red"); public static final Color BLUE = fromString("blue");}
Union of other union/enum, basic type and literals of that type
import "@azure-tools/typespec-azure-resource-manager";
union ProvisioningState { string, "InProgress", Azure.ResourceManager.ResourceProvisioningState,}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{ "kind": "enum", "name": "ProvisioningState", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "InProgress", "value": "InProgress" }, { "kind": "enumvalue", "name": "Succeeded", "value": "Succeeded" }, { "kind": "enumvalue", "name": "Failed", "value": "Failed" }, { "kind": "enumvalue", "name": "Canceled", "value": "Canceled" } ], "isFixed": false, "isUnionAsEnum": true}
With flatten-union-as-enum
flagged false
:
{ "kind": "union", "name": "ProvisioningState", "generatedName": false, "values": [ { "kind": "string" }, { "kind": "constant", "value": "InProgress", "valueType": { "kind": "string" } }, { "kind": "enum", "name": "ResourceProvisioningState", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "Succeeded", "value": "Succeeded" }, { "kind": "enumvalue", "name": "Failed", "value": "Failed" }, { "kind": "enumvalue", "name": "Canceled", "value": "Canceled" } ], "isFixed": true, "isUnionAsEnum": false } ]}
Python generates a single open enum.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class ProvisioningState(str, Enum, metaclass=CaseInsensitiveEnumMeta): INPROGRESS = "InProgress" SUCCEEDED = "Succeeded" FAILED = "Failed" CANCELED = "Canceled"
public readonly partial struct ProvisioningState : IEquatable<ProvisioningState>{ private const string SucceededValue = "Succeeded"; private const string FailedValue = "Failed"; private const string CanceledValue = "Canceled"; private const string InProgressValue = "InProgress";
public static ProvisioningState Succeeded { get; } = new ProvisioningState(SucceededValue); public static ProvisioningState Failed { get; } = new ProvisioningState(FailedValue); public static ProvisioningState Canceled { get; } = new ProvisioningState(CanceledValue); public static ProvisioningState InProgress { get; } = new ProvisioningState(InProgressValue);}
export type ResourceProvisioningState = "Succeeded" | "Failed" | "Canceled";// NOTE: extensible enum design may change in JSexport type ProvisioningState = string | "InProgress" | ResourceProvisioningState;
public final class ProvisioningState extends ExpandableStringEnum<ProvisioningState> { public static final ProvisioningState INPROGRESS = fromString("InProgress"); public static final ProvisioningState SUCCEEDED = fromString("Succeeded"); public static final ProvisioningState FAILED = fromString("Failed"); public static final ProvisioningState CANCELED = fromString("Canceled");}
Union of other unions of literals with same type
union LR { left: "left", right: "right",}
union UD { up: "up", down: "down",}
union Orientation { LR, UD,}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{ "kind": "enum", "name": "Orientation", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" }, { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true}
With flatten-union-as-enum
flagged false
:
{ "kind": "union", "name": "Orientation", "generatedName": false, "values": [ { "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true }, { "kind": "enum", "name": "UD", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true } ]}
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Orientation(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right" UP = "up" DOWN = "down"
public enum Orientation{ Left, Right, Up, Down}
export type LR = "left" | "right";export type UD = "up" | "down";export type Orientation = LR | UD;
public enum Orientation { LEFT("left"), RIGHT("right"), UP("up"), DOWN("down");}
Inline union of other unions of literals with same type
union LR { left: "left", right: "right",}
union UD { up: "up", down: "down",}
model Widget { orientation: LR | UD;}
For union of other union or enum. TCGC will do the flatten according to the flag.
With flatten-union-as-enum
flagged true
:
{ "kind": "enum", "name": "WidgetOrientations", "generatedName": true, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" }, { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true}
With flatten-union-as-enum
flagged false
:
{ "kind": "union", "name": "WidgetOrientations", "generatedName": true, "values": [ { "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": true }, { "kind": "enum", "name": "UD", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": true } ]}
Since this is inline, Python will generate this as a single union of all possible literal values.
from typing import Literal
type WidgetOrientation = "left" | "right" | "up" | "down" | str
model Widget: orientation: WidgetOrientation
public partial class Widget{ public WidgetOrientation Orientation;}public enum WidgetOrientation{ Left, Right, Up, Down}
export interface Widget { orientation: LR | UD;}
export type LR = "left" | "right";export type UD = "up" | "down";
public enum WidgetOrientation { LEFT("left"), RIGHT("right"), UP("up"), DOWN("down");}
Union with multiple types
These are unions where the values don’t share same type.
model Shirt { sizing: 32 | 34 | int32 | "small" | "medium" | string;}
{ "kind": "union", "name": "ShirtSizings", "generatedName": true, "values": [ { "kind": "constant", "value": 32, "valueType": { "kind": "int32" } }, { "kind": "constant", "value": 34, "valueType": { "kind": "int32" } }, { "kind": "constant", "value": "small", "valueType": { "kind": "string" } }, { "kind": "constant", "value": "medium", "valueType": { "kind": "string" } }, { "kind": "string" } ]}
Python will generate this as a union since these entries don’t share the same type
from typing import Literal
type ShirtSizing = Literal[32] | Literal[34] | int | Literal["small"] | Literal["medium"] | str
model Shirt: sizing: ShirtSizing
public partial class Shirt{ public BinaryData Shirt;}
export interface Shirt { sizing: 32 | 34 | number | "small" | "medium" | string;}
public final class Shirt { private BinaryData sizing;}
Enums
Standard
Standard enums will be generated as closed enums.
enum LR { left, right,}
{ "kind": "enum", "name": "LR", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" } ], "isFixed": true, "isUnionAsEnum": false}
Python never generates closed enums by design. We will always permit users to pass in additional values.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right"
public enum LR{ Left, Right}
export type LR = "left" | "right";
public enum LR { LEFT("left"), RIGHT("right");}
Versioning Enums
@versioned(Versions)@servicenamespace My.Service;
enum Versions { v1, v2,}
{ "kind": "enum", "name": "Versions", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "v1", "value": "v1" }, { "kind": "enumvalue", "name": "v2", "value": "v2" } ], "isFixed": true, "isUnionAsEnum": false, "usage": 8}
# Python does not generate the enum used for versioning
// CSharp does not generate the enum used for versioning
// JS does not generate the enum used for versioning
public enum ServiceServiceVersion implements ServiceVersion { V1("v1"), V2("v2");}
Spread
Spreading enums will return the resultant enum as a new single closed enum.
enum LR { left, right,}
enum UD { up, down,}
enum Orientation { ...LR, ...UD,}
{ "kind": "enum", "name": "Orientation", "generatedName": false, "valueType": { "kind": "string" }, "values": [ { "kind": "enumvalue", "name": "left", "value": "left" }, { "kind": "enumvalue", "name": "right", "value": "right" }, { "kind": "enumvalue", "name": "up", "value": "up" }, { "kind": "enumvalue", "name": "down", "value": "down" } ], "isFixed": true, "isUnionAsEnum": false}
Python generates one open enum, because Python never generates an enum as fully closed.
from enum import Enumfrom corehttp.utils import CaseInsensitiveEnumMeta
class Orientation(str, Enum, metaclass=CaseInsensitiveEnumMeta): LEFT = "left" RIGHT = "right" UP = "up" DOWN = "down"
public enum Orientation{ Left, Right, Up, Down}
export type Orientation = "left" | "right" | "up" | "down";
public enum Orientation { LEFT("left"), RIGHT("right"), UP("up"), DOWN("down");}
Scalars
Encoding
We will take the @encode
decorator into account, determining how we serialize inputted scalars to send over the wire.
model Test { @encode(DateTimeKnownEncoding.rfc3339) prop: utcDateTime;}
{ "kind": "property", "name": "prop", "type": { "kind": "utcDateTime", "encode": "rfc3339", "wireType": { "kind": "string" } }}
serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="rfc3339")
// Internal implementationutf8JsonWriter.WriteStringValue(Prop.ToString());
TODO;
// Internal implementationjsonWriter.writeStringField("prop", this.value == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.value));
When you specify an encoding type, say that you want to encode an integer as a string, that will also be represented in our generated SDKs.
model Test { @encode(string) prop: int64;}
{ "kind": "property", "name": "prop", "type": { "kind": "int64", "encode": "string", "wireType": { "kind": "string" } }}
serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="string")
TODO
TODO;
// Internal implementationjsonWriter.writeStringField("prop", Objects.toString(this.value, null));
Namespace
The namespace for models, enums, and unions will follow the namespace they belong to. You can use @clientNamespace
to override it if needed.
namespace My.Service;
model Foo { prop: string;}
@clientNamespace("My.Service.Temp")model Bar { prop: string;}
from my.service import Foofrom my.service.temp import Bar
foo = Foo(prop="hello")bar = Bar(prop="world")
TODO
TODO;
As flavor=azure
, Java emitter generates the model classes under models
package.
import my.service.models.Foo;import my.service.temp.models.Bar;
Foo foo = new Foo("hello");Bar bar = new Bar("world");