/// <summary> /// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmStructuredType"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="structuredType">The Edm structured type.</param> /// <returns>The created <see cref="OpenApiSchema"/>.</returns> public static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); return(context.CreateStructuredTypeSchema(structuredType, true, true)); }
public void CreateEntityTypeWithoutBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel; ODataContext context = new ODataContext(model, new OpenApiConvertSettings { ShowSchemaExamples = true }); IEdmEntityType entity = model.SchemaElements.OfType <IEdmEntityType>().First(t => t.Name == "Zoo"); Assert.NotNull(entity); // Guard // Act var schema = context.CreateStructuredTypeSchema(entity); // Assert Assert.NotNull(schema); Assert.Equal("object", schema.Type); Assert.Null(schema.AllOf); Assert.NotNull(schema.Properties); Assert.Equal(2, schema.Properties.Count); Assert.Equal(new string[] { "Id", "Creatures" }, schema.Properties.Select(e => e.Key)); Assert.Equal("Entity type 'Zoo' description.", schema.Description); Assert.Equal("Zoo", schema.Title); // Act string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); // Assert Assert.NotNull(json); Assert.Equal(@"{ ""title"": ""Zoo"", ""type"": ""object"", ""properties"": { ""Id"": { ""maximum"": 2147483647, ""minimum"": -2147483648, ""type"": ""integer"", ""format"": ""int32"" }, ""Creatures"": { ""type"": ""array"", ""items"": { ""$ref"": ""#/components/schemas/NS.Creature"" } } }, ""description"": ""Entity type 'Zoo' description."", ""example"": { ""Id"": ""integer (identifier)"", ""Creatures"": [ { ""@odata.type"": ""NS.Creature"" } ] } }".ChangeLineBreaks(), json); }
public void CreateStructuredTypeSchemaThrowArgumentNullEnumType() { // Arrange ODataContext context = new ODataContext(EdmCoreModel.Instance); // Act & Assert Assert.Throws <ArgumentNullException>("structuredType", () => context.CreateStructuredTypeSchema(structuredType: null)); }
public void CreateStructuredTypeSchemaThrowArgumentNullContext() { // Arrange ODataContext context = null; // Act & Assert Assert.Throws <ArgumentNullException>("context", () => context.CreateStructuredTypeSchema(structuredType: null)); }
public void CreateComplexTypeWithoutBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel; ODataContext context = new ODataContext(model, new OpenApiConvertSettings { ShowSchemaExamples = true }); IEdmComplexType complex = model.SchemaElements.OfType <IEdmComplexType>().First(t => t.Name == "Address"); Assert.NotNull(complex); // Guard // Act var schema = context.CreateStructuredTypeSchema(complex); // Assert Assert.NotNull(schema); Assert.Equal("object", schema.Type); Assert.Null(schema.AllOf); Assert.NotNull(schema.Properties); Assert.Equal(2, schema.Properties.Count); Assert.Equal(new string[] { "Street", "City" }, schema.Properties.Select(e => e.Key)); Assert.Equal("Complex type 'Address' description.", schema.Description); Assert.Equal("Address", schema.Title); // Act string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); // Assert Assert.NotNull(json); Assert.Equal(@"{ ""title"": ""Address"", ""type"": ""object"", ""properties"": { ""Street"": { ""type"": ""string"", ""nullable"": true }, ""City"": { ""type"": ""string"", ""nullable"": true } }, ""description"": ""Complex type 'Address' description."", ""example"": { ""Street"": ""string"", ""City"": ""string"" } }".ChangeLineBreaks(), json); }
public void CreateEntityTypeWithCrossReferenceBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences; ODataContext context = new ODataContext(model, new OpenApiConvertSettings { ShowSchemaExamples = true }); IEdmEntityType entity = model.SchemaElements.OfType <IEdmEntityType>().First(t => t.Name == "Customer"); Assert.NotNull(entity); // Guard // Act var schema = context.CreateStructuredTypeSchema(entity); // Assert Assert.NotNull(schema); Assert.True(String.IsNullOrEmpty(schema.Type)); Assert.NotNull(schema.AllOf); Assert.Null(schema.AnyOf); Assert.Null(schema.OneOf); Assert.Null(schema.Properties); Assert.Equal(2, schema.AllOf.Count); var baseSchema = schema.AllOf.First(); Assert.NotNull(baseSchema.Reference); Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type); Assert.Equal("SubNS.CustomerBase", baseSchema.Reference.Id); var declaredSchema = schema.AllOf.Last(); Assert.Equal("object", declaredSchema.Type); Assert.Null(declaredSchema.AllOf); Assert.Null(declaredSchema.AnyOf); Assert.Null(declaredSchema.OneOf); Assert.NotNull(declaredSchema.Properties); Assert.Equal(1, declaredSchema.Properties.Count); var property = Assert.Single(declaredSchema.Properties); Assert.Equal("Extra", property.Key); Assert.Equal("integer", property.Value.Type); Assert.Null(property.Value.OneOf); Assert.Equal("Customer", declaredSchema.Title); }
/// <summary> /// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmTypeReference"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="edmTypeReference">The Edm type reference.</param> /// <returns>The created <see cref="OpenApiSchema"/>.</returns> public static OpenApiSchema CreateEdmTypeSchema(this ODataContext context, IEdmTypeReference edmTypeReference) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(edmTypeReference, nameof(edmTypeReference)); switch (edmTypeReference.TypeKind()) { case EdmTypeKind.Collection: // Collection-valued structural and navigation are represented as Schema Objects of type array. // The value of the items keyword is a Schema Object specifying the type of the items. return(new OpenApiSchema { Type = "array", Items = context.CreateEdmTypeSchema(edmTypeReference.AsCollection().ElementType()) }); // Complex, enum, entity, entity reference are represented as JSON References to the Schema Object of the complex, // enum, entity and entity reference type, either as local references for types directly defined in the CSDL document, // or as external references for types defined in referenced CSDL documents. case EdmTypeKind.Complex: case EdmTypeKind.Entity: return(context.CreateStructuredTypeSchema(edmTypeReference.AsStructured())); case EdmTypeKind.Enum: return(context.CreateEnumTypeSchema(edmTypeReference.AsEnum())); // Primitive properties of type Edm.PrimitiveType, Edm.Stream, and any of the Edm.Geo* types are // represented as Schema Objects that are JSON References to definitions in the Definitions Object case EdmTypeKind.Primitive: IEdmPrimitiveTypeReference primitiveTypeReference = (IEdmPrimitiveTypeReference)edmTypeReference; return(context.CreateSchema(primitiveTypeReference)); case EdmTypeKind.TypeDefinition: return(context.CreateSchema(((IEdmTypeDefinitionReference)edmTypeReference).TypeDefinition().UnderlyingType)); case EdmTypeKind.EntityReference: return(context.CreateTypeDefinitionSchema(edmTypeReference.AsTypeDefinition())); case EdmTypeKind.None: default: throw Error.NotSupported(String.Format(SRResource.NotSupportedEdmTypeKind, edmTypeReference.TypeKind())); } }
internal static OpenApiSchema CreateSchemaTypeSchema(this ODataContext context, IEdmType edmType) { Debug.Assert(context != null); Debug.Assert(edmType != null); switch (edmType.TypeKind) { case EdmTypeKind.Complex: // complex type case EdmTypeKind.Entity: // entity type return(context.CreateStructuredTypeSchema((IEdmStructuredType)edmType, true, true)); case EdmTypeKind.Enum: // enum type return(context.CreateEnumTypeSchema((IEdmEnumType)edmType)); case EdmTypeKind.TypeDefinition: // type definition return(context.CreateSchemaTypeDefinitionSchema((IEdmTypeDefinition)edmType)); case EdmTypeKind.None: default: throw Error.NotSupported(String.Format(SRResource.NotSupportedEdmTypeKind, edmType.TypeKind)); } }
public void CreateEntityTypeWithBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel; ODataContext context = new ODataContext(model, new OpenApiConvertSettings { ShowSchemaExamples = true }); IEdmEntityType entity = model.SchemaElements.OfType <IEdmEntityType>().First(t => t.Name == "Human"); Assert.NotNull(entity); // Guard // Act var schema = context.CreateStructuredTypeSchema(entity); // Assert Assert.NotNull(schema); Assert.True(String.IsNullOrEmpty(schema.Type)); Assert.NotNull(schema.AllOf); Assert.Null(schema.AnyOf); Assert.Null(schema.OneOf); Assert.Null(schema.Properties); Assert.Equal(2, schema.AllOf.Count); var baseSchema = schema.AllOf.First(); Assert.NotNull(baseSchema.Reference); Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type); Assert.Equal("NS.Animal", baseSchema.Reference.Id); var declaredSchema = schema.AllOf.Last(); Assert.Equal("object", declaredSchema.Type); Assert.Null(declaredSchema.AllOf); Assert.Null(declaredSchema.AnyOf); Assert.Null(declaredSchema.OneOf); Assert.NotNull(declaredSchema.Properties); Assert.Equal(1, declaredSchema.Properties.Count); var property = Assert.Single(declaredSchema.Properties); Assert.Equal("Name", property.Key); Assert.Equal("string", property.Value.Type); Assert.Null(property.Value.OneOf); Assert.Equal("Entity type 'Human' description.", declaredSchema.Description); Assert.Equal("Human", declaredSchema.Title); // Act string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); _output.WriteLine(json); // Assert Assert.NotNull(json); Assert.Equal(@"{ ""allOf"": [ { ""$ref"": ""#/components/schemas/NS.Animal"" }, { ""title"": ""Human"", ""type"": ""object"", ""properties"": { ""Name"": { ""type"": ""string"" } }, ""description"": ""Entity type 'Human' description."" } ], ""example"": { ""Id"": ""integer (identifier)"", ""Age"": ""integer"", ""Name"": ""string"" } }" .ChangeLineBreaks(), json); }
public void CreateComplexTypeWithBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel; ODataContext context = new ODataContext(model, new OpenApiConvertSettings { IEEE754Compatible = true, ShowSchemaExamples = true }); IEdmComplexType complex = model.SchemaElements.OfType <IEdmComplexType>().First(t => t.Name == "Tree"); Assert.NotNull(complex); // Guard // Act var schema = context.CreateStructuredTypeSchema(complex); // Assert Assert.NotNull(schema); Assert.True(String.IsNullOrEmpty(schema.Type)); Assert.NotNull(schema.AllOf); Assert.Null(schema.AnyOf); Assert.Null(schema.OneOf); Assert.Null(schema.Properties); Assert.Equal(2, schema.AllOf.Count); var baseSchema = schema.AllOf.First(); Assert.NotNull(baseSchema.Reference); Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type); Assert.Equal("NS.LandPlant", baseSchema.Reference.Id); var declaredSchema = schema.AllOf.Last(); Assert.Equal("object", declaredSchema.Type); Assert.Null(declaredSchema.AllOf); Assert.Null(declaredSchema.AnyOf); Assert.Null(declaredSchema.OneOf); Assert.NotNull(declaredSchema.Properties); Assert.Equal(1, declaredSchema.Properties.Count); var property = Assert.Single(declaredSchema.Properties); Assert.Equal("Price", property.Key); Assert.Equal("decimal", property.Value.Format); Assert.NotNull(property.Value.AnyOf); Assert.Equal(new string[] { "number", "string" }, property.Value.AnyOf.Select(e => e.Type)); Assert.Equal("Complex type 'Tree' description.", declaredSchema.Description); Assert.Equal("Tree", declaredSchema.Title); // Act string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); // Assert Assert.NotNull(json); Assert.Equal(@"{ ""allOf"": [ { ""$ref"": ""#/components/schemas/NS.LandPlant"" }, { ""title"": ""Tree"", ""type"": ""object"", ""properties"": { ""Price"": { ""multipleOf"": 1, ""anyOf"": [ { ""type"": ""number"" }, { ""type"": ""string"" } ], ""format"": ""decimal"" } }, ""description"": ""Complex type 'Tree' description."" } ], ""example"": { ""Color"": { ""@odata.type"": ""NS.Color"" }, ""Continent"": { ""@odata.type"": ""NS.Continent"" }, ""Name"": ""string"", ""Price"": ""decimal"" } }" .ChangeLineBreaks(), json); }
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample, IEnumerable <IEdmStructuredType> derivedTypes = null) { Debug.Assert(context != null); Debug.Assert(structuredType != null); IOpenApiAny example = null; if (context.Settings.ShowSchemaExamples) { example = CreateStructuredTypePropertiesExample(context, structuredType); } if (context.Settings.EnableDiscriminatorValue && derivedTypes == null) { derivedTypes = context.Model.FindAllDerivedTypes(structuredType); } if (processBase && structuredType.BaseType != null) { // The x-ms-discriminator-value extension is added to structured types which are derived types. Dictionary <string, IOpenApiExtension> extension = null; if (context.Settings.EnableDiscriminatorValue && !derivedTypes.Any()) { extension = new Dictionary <string, IOpenApiExtension> { { Constants.xMsDiscriminatorValue, new OpenApiString("#" + structuredType.FullTypeName()) } }; } // A structured type with a base type is represented as a Schema Object // that contains the keyword allOf whose value is an array with two items: return(new OpenApiSchema { Extensions = extension, AllOf = new List <OpenApiSchema> { // 1. a JSON Reference to the Schema Object of the base type new OpenApiSchema { UnresolvedReference = true, Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = structuredType.BaseType.FullTypeName() } }, // 2. a Schema Object describing the derived type context.CreateStructuredTypeSchema(structuredType, false, false, derivedTypes) }, AnyOf = null, OneOf = null, Properties = null, Example = example }); } else { // The discriminator object is added to structured types which have derived types. OpenApiDiscriminator discriminator = null; if (context.Settings.EnableDiscriminatorValue && derivedTypes.Any()) { Dictionary <string, string> mapping = derivedTypes .ToDictionary(x => $"#{x.FullTypeName()}", x => new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = x.FullTypeName() } }.Reference.ReferenceV3); discriminator = new OpenApiDiscriminator { PropertyName = Constants.OdataType, Mapping = mapping }; } // A structured type without a base type is represented as a Schema Object of type object OpenApiSchema schema = new() { Title = (structuredType as IEdmSchemaElement)?.Name, Type = "object", Discriminator = discriminator, // Each structural property and navigation property is represented // as a name/value pair of the standard OpenAPI properties object. Properties = context.CreateStructuredTypePropertiesSchema(structuredType), // make others null AllOf = null, OneOf = null, AnyOf = null }; if (context.Settings.EnableDiscriminatorValue) { if (!schema.Properties.TryAdd(Constants.OdataType, new OpenApiSchema() { Type = "string", Default = new OpenApiString("#" + structuredType.FullTypeName()), })) { throw new InvalidOperationException( $"Property {Constants.OdataType} is already present in schema {structuredType.FullTypeName()}; verify CSDL."); } schema.Required.Add(Constants.OdataType); } // It optionally can contain the field description, // whose value is the value of the unqualified annotation Core.Description of the structured type. if (structuredType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complex = (IEdmComplexType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(complex); } else if (structuredType.TypeKind == EdmTypeKind.Entity) { IEdmEntityType entity = (IEdmEntityType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(entity); } if (processExample) { schema.Example = example; } return(schema); } }
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample) { Debug.Assert(context != null); Debug.Assert(structuredType != null); if (processBase && structuredType.BaseType != null) { // A structured type with a base type is represented as a Schema Object // that contains the keyword allOf whose value is an array with two items: return(new OpenApiSchema { AllOf = new List <OpenApiSchema> { // 1. a JSON Reference to the Schema Object of the base type new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = structuredType.BaseType.FullTypeName() } }, // 2. a Schema Object describing the derived type context.CreateStructuredTypeSchema(structuredType, false, false) }, AnyOf = null, OneOf = null, Properties = null, Example = CreateStructuredTypePropertiesExample(context, structuredType) }); } else { // A structured type without a base type is represented as a Schema Object of type object OpenApiSchema schema = new OpenApiSchema { Title = (structuredType as IEdmSchemaElement)?.Name, Type = "object", // Each structural property and navigation property is represented // as a name/value pair of the standard OpenAPI properties object. Properties = context.CreateStructuredTypePropertiesSchema(structuredType), // make others null AllOf = null, OneOf = null, AnyOf = null }; // It optionally can contain the field description, // whose value is the value of the unqualified annotation Core.Description of the structured type. if (structuredType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complex = (IEdmComplexType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(complex); } else if (structuredType.TypeKind == EdmTypeKind.Entity) { IEdmEntityType entity = (IEdmEntityType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(entity); } if (processExample) { schema.Example = CreateStructuredTypePropertiesExample(context, structuredType); } return(schema); } }
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample, IEnumerable <IEdmEntityType> derivedTypes = null) { Debug.Assert(context != null); Debug.Assert(structuredType != null); if (context.Settings.EnableDiscriminatorValue && derivedTypes == null) { derivedTypes = context.Model.FindDirectlyDerivedTypes(structuredType).OfType <IEdmEntityType>(); } if (processBase && structuredType.BaseType != null) { // The x-ms-discriminator-value extension is added to structured types which are derived types. Dictionary <string, IOpenApiExtension> extension = null; if (context.Settings.EnableDiscriminatorValue && !derivedTypes.Any()) { extension = new Dictionary <string, IOpenApiExtension> { { Constants.xMsDiscriminatorValue, new OpenApiString("#" + structuredType.FullTypeName()) } }; } // A structured type with a base type is represented as a Schema Object // that contains the keyword allOf whose value is an array with two items: return(new OpenApiSchema { Extensions = extension, AllOf = new List <OpenApiSchema> { // 1. a JSON Reference to the Schema Object of the base type new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = structuredType.BaseType.FullTypeName() } }, // 2. a Schema Object describing the derived type context.CreateStructuredTypeSchema(structuredType, false, false, derivedTypes) }, AnyOf = null, OneOf = null, Properties = null, Example = CreateStructuredTypePropertiesExample(context, structuredType) }); } else { // The discriminator object is added to structured types which have derived types. OpenApiDiscriminator discriminator = null; if (context.Settings.EnableDiscriminatorValue && derivedTypes.Any() && structuredType.BaseType != null) { discriminator = new OpenApiDiscriminator { PropertyName = "@odata.type" }; } // A structured type without a base type is represented as a Schema Object of type object OpenApiSchema schema = new OpenApiSchema { Title = (structuredType as IEdmSchemaElement)?.Name, Type = "object", Discriminator = discriminator, // Each structural property and navigation property is represented // as a name/value pair of the standard OpenAPI properties object. Properties = context.CreateStructuredTypePropertiesSchema(structuredType), // make others null AllOf = null, OneOf = null, AnyOf = null }; // It optionally can contain the field description, // whose value is the value of the unqualified annotation Core.Description of the structured type. if (structuredType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complex = (IEdmComplexType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(complex); } else if (structuredType.TypeKind == EdmTypeKind.Entity) { IEdmEntityType entity = (IEdmEntityType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(entity); } if (processExample) { schema.Example = CreateStructuredTypePropertiesExample(context, structuredType); } return(schema); } }