Beispiel #1
0
        /// <summary>
        /// Create key parameters for the <see cref="ODataKeySegment"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="keySegment">The key segment.</param>
        /// <param name="parameterNameMapping">The parameter name mapping.</param>
        /// <returns>The created the list of <see cref="OpenApiParameter"/>.</returns>
        public static IList <OpenApiParameter> CreateKeyParameters(this ODataContext context, ODataKeySegment keySegment,
                                                                   IDictionary <string, string> parameterNameMapping = null)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(keySegment, nameof(keySegment));

            IList <OpenApiParameter> parameters = new List <OpenApiParameter>();
            IEdmEntityType           entityType = keySegment.EntityType;

            IList <IEdmStructuralProperty> keys = entityType.Key().ToList();

            if (keys.Count() == 1)
            {
                string keyName = keys.First().Name;

                // If dictionary parameterNameMapping is defined, there's no need of setting the
                // keyName, we will retrieve this from the dictionary key.
                if (context.Settings.PrefixEntityTypeNameBeforeKey && parameterNameMapping == null)
                {
                    keyName = entityType.Name + "-" + keys.First().Name;
                }

                OpenApiParameter parameter = new OpenApiParameter
                {
                    Name        = parameterNameMapping == null ? keyName: parameterNameMapping[keyName],
                    In          = ParameterLocation.Path,
                    Required    = true,
                    Description = "key: " + keyName + " of " + entityType.Name,
                    Schema      = context.CreateEdmTypeSchema(keys.First().Type)
                };

                parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                parameters.Add(parameter);
            }
            else
            {
                // append key parameter
                foreach (var keyProperty in entityType.Key())
                {
                    OpenApiParameter parameter = new OpenApiParameter
                    {
                        Name = parameterNameMapping == null ?
                               keyProperty.Name:
                               parameterNameMapping[keyProperty.Name],// By design: not prefix with type name if enable type name prefix
                        In          = ParameterLocation.Path,
                        Required    = true,
                        Description = "key: " + keyProperty.Name + " of " + entityType.Name,
                        Schema      = context.CreateEdmTypeSchema(keyProperty.Type)
                    };

                    parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                    parameters.Add(parameter);
                }
            }

            return(parameters);
        }
Beispiel #2
0
        /// <summary>
        /// Create key parameters for the <see cref="ODataKeySegment"/>.
        /// </summary>
        /// <param name="keySegment">The key segment.</param>
        /// <returns>The created the list of <see cref="OpenApiParameter"/>.</returns>
        public static IList <OpenApiParameter> CreateKeyParameters(this ODataContext context, ODataKeySegment keySegment)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(keySegment, nameof(keySegment));

            IList <OpenApiParameter> parameters = new List <OpenApiParameter>();
            IEdmEntityType           entityType = keySegment.EntityType;

            IList <IEdmStructuralProperty> keys = entityType.Key().ToList();

            if (keys.Count() == 1)
            {
                string keyName = keys.First().Name + keySegment.KeyIndex.ToString();
                if (context.Settings.PrefixEntityTypeNameBeforeKey)
                {
                    keyName = entityType.Name + "-" + keyName;
                }

                OpenApiParameter parameter = new OpenApiParameter
                {
                    Name        = keyName,
                    In          = ParameterLocation.Path,
                    Required    = true,
                    Description = "key: " + keyName,
                    Schema      = context.CreateEdmTypeSchema(keys.First().Type)
                };

                parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                parameters.Add(parameter);
            }
            else
            {
                // append key parameter
                foreach (var keyProperty in entityType.Key())
                {
                    string keyName = keyProperty.Name + keySegment.KeyIndex.ToString();

                    OpenApiParameter parameter = new OpenApiParameter
                    {
                        Name        = keyName,
                        In          = ParameterLocation.Path,
                        Required    = true,
                        Description = "key: " + keyName,
                        Schema      = context.CreateEdmTypeSchema(keyProperty.Type)
                    };

                    parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
                    parameters.Add(parameter);
                }
            }

            return(parameters);
        }
Beispiel #3
0
        /// <summary>
        /// Create the <see cref="OpenApiResponses"/> for a <see cref="IEdmOperation"/>
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="operation">The Edm operation.</param>
        /// <returns>The created <see cref="OpenApiResponses"/>.</returns>
        public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(operation, nameof(operation));

            OpenApiResponses responses = new OpenApiResponses();

            if (operation.ReturnType != null)
            {
                if (operation.IsAction())
                {
                    //responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
                    OpenApiResponse response = new OpenApiResponse
                    {
                        Description = "Success",
                        Content     = new Dictionary <string, OpenApiMediaType>
                        {
                            {
                                Constants.ApplicationJsonMediaType,
                                new OpenApiMediaType
                                {
                                    Schema = context.CreateEdmTypeSchema(operation.ReturnType)
                                }
                            }
                        }
                    };
                    responses.Add(Constants.StatusCode200, response);
                }
                else
                {
                    OpenApiResponse response = new OpenApiResponse
                    {
                        Description = "Success",
                        Content     = new Dictionary <string, OpenApiMediaType>
                        {
                            {
                                Constants.ApplicationJsonMediaType,
                                new OpenApiMediaType
                                {
                                    Schema = context.CreateEdmTypeSchema(operation.ReturnType)
                                }
                            }
                        }
                    };
                    responses.Add(Constants.StatusCode200, response);
                }
            }
            // both action & function has the default response.
            responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());

            return(responses);
        }
Beispiel #4
0
        public void CreateEdmTypeSchemaReturnSchemaForNullableCollectionComplexType()
        {
            // Arrange
            IEdmModel                   model          = EdmModelHelper.TripServiceModel;
            IEdmComplexType             complex        = model.SchemaElements.OfType <IEdmComplexType>().First(c => c.Name == "AirportLocation");
            ODataContext                context        = new ODataContext(model);
            IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
                new EdmCollectionType(new EdmComplexTypeReference(complex, true)));

            // Act
            var schema = context.CreateEdmTypeSchema(collectionType);

            Assert.NotNull(schema);
            string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);

            // & Assert
            Assert.Equal(@"{
  ""type"": ""array"",
  ""items"": {
    ""anyOf"": [
      {
        ""$ref"": ""#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation""
      }
    ],
    ""nullable"": true
  }
}".ChangeLineBreaks(), json);
        }
Beispiel #5
0
        public void CreateEdmTypeSchemaReturnSchemaForEntityType(bool isNullable)
        {
            // Arrange
            IEdmModel      model  = EdmModelHelper.TripServiceModel;
            IEdmEntityType entity = model.SchemaElements.OfType <IEdmEntityType>().First(c => c.Name == "Manager");

            Assert.NotNull(entity); // guard
            IEdmEntityTypeReference entityTypeReference = new EdmEntityTypeReference(entity, isNullable);
            ODataContext            context             = new ODataContext(model);

            // Act
            var schema = context.CreateEdmTypeSchema(entityTypeReference);

            // & Assert
            Assert.NotNull(schema);

            if (isNullable)
            {
                Assert.Null(schema.Reference);
                Assert.NotNull(schema.AnyOf);
                Assert.NotEmpty(schema.AnyOf);
                var anyOf = Assert.Single(schema.AnyOf);
                Assert.NotNull(anyOf.Reference);
                Assert.Equal(ReferenceType.Schema, anyOf.Reference.Type);
                Assert.Equal(entity.FullTypeName(), anyOf.Reference.Id);
            }
            else
            {
                Assert.Null(schema.AnyOf);
                Assert.NotNull(schema.Reference);
                Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
                Assert.Equal(entity.FullTypeName(), schema.Reference.Id);
            }
        }
        public void CreateEdmTypeSchemaReturnSchemaForNullableCollectionPrimitiveType()
        {
            // Arrange
            IEdmModel    model   = EdmCoreModel.Instance;
            ODataContext context = new ODataContext(model);
            IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
                new EdmCollectionType(EdmCoreModel.Instance.GetInt32(true)));

            // Act
            var schema = context.CreateEdmTypeSchema(collectionType);

            Assert.NotNull(schema);
            string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);

            // & Assert
            Assert.Equal(@"{
  ""type"": ""array"",
  ""items"": {
    ""maximum"": 2147483647,
    ""minimum"": -2147483648,
    ""type"": ""integer"",
    ""format"": ""int32"",
    ""nullable"": true
  }
}".ChangeLineBreaks(), json);
        }
        public void CreateEdmTypeSchemaReturnSchemaForInt32(bool isNullable)
        {
            // Arrange
            IEdmModel         model            = EdmCoreModel.Instance;
            ODataContext      context          = new ODataContext(model);
            IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetInt32(isNullable);

            // Act
            var schema = context.CreateEdmTypeSchema(edmTypeReference);

            Assert.NotNull(schema); // guard
            string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);

            // & Assert
            if (isNullable)
            {
                Assert.Equal(@"{
  ""maximum"": 2147483647,
  ""minimum"": -2147483648,
  ""type"": ""integer"",
  ""format"": ""int32"",
  ""nullable"": true
}".ChangeLineBreaks(), json);
            }
            else
            {
                Assert.Equal(@"{
  ""maximum"": 2147483647,
  ""minimum"": -2147483648,
  ""type"": ""integer"",
  ""format"": ""int32""
}".ChangeLineBreaks(), json);
            }
        }
        /// <summary>
        /// Create a map of string/<see cref="OpenApiSchema"/> map for a <see cref="IEdmStructuredType"/>'s all properties.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="structuredType">The Edm structured type.</param>
        /// <returns>The created map of <see cref="OpenApiSchema"/>.</returns>
        public static IDictionary <string, OpenApiSchema> CreateStructuredTypePropertiesSchema(this ODataContext context, IEdmStructuredType structuredType)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(structuredType, nameof(structuredType));

            // The name is the property name, the value is a Schema Object describing the allowed values of the property.
            IDictionary <string, OpenApiSchema> properties = new Dictionary <string, OpenApiSchema>();

            // structure properties
            foreach (var property in structuredType.DeclaredStructuralProperties())
            {
                OpenApiSchema propertySchema = context.CreatePropertySchema(property);
                propertySchema.Description = context.Model.GetDescriptionAnnotation(property);
                propertySchema.Extensions.AddCustomAtributesToExtensions(context, property);
                properties.Add(property.Name, propertySchema);
            }

            // navigation properties
            foreach (var property in structuredType.DeclaredNavigationProperties())
            {
                OpenApiSchema propertySchema = context.CreateEdmTypeSchema(property.Type);
                propertySchema.Description = context.Model.GetDescriptionAnnotation(property);
                propertySchema.Extensions.AddCustomAtributesToExtensions(context, property);
                properties.Add(property.Name, propertySchema);
            }

            return(properties);
        }
        public void CreateEdmTypeSchemaReturnSchemaForInt64(bool isNullable, bool IEEE754Compatible)
        {
            // Arrange
            IEdmModel model = EdmCoreModel.Instance;
            OpenApiConvertSettings settings = new OpenApiConvertSettings
            {
                IEEE754Compatible = IEEE754Compatible
            };

            ODataContext      context          = new ODataContext(model, settings);
            IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetInt64(isNullable);

            // Act
            var schema = context.CreateEdmTypeSchema(edmTypeReference);

            Assert.NotNull(schema); // guard

            // & Assert
            if (IEEE754Compatible)
            {
                Assert.Null(schema.Type);
                Assert.NotNull(schema.AnyOf);
                Assert.Equal(2, schema.AnyOf.Count);
                Assert.Equal(new[] { "integer", "string" }, schema.AnyOf.Select(a => a.Type));
            }
            else
            {
                Assert.Equal("integer", schema.Type);
                Assert.Null(schema.AnyOf);
            }

            Assert.Equal(isNullable, schema.Nullable);
        }
        /// <summary>
        /// Create a map of string/<see cref="OpenApiSchema"/> map for a <see cref="IEdmStructuredType"/>'s all properties.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="structuredType">The Edm structured type.</param>
        /// <returns>The created map of <see cref="OpenApiSchema"/>.</returns>
        public static IDictionary <string, OpenApiSchema> CreateStructuredTypeCombinedPropertiesSchema(this ODataContext context, IEdmStructuredType structuredType)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(structuredType, nameof(structuredType));

            // The name is the property name, the value is a Schema Object describing the allowed values of the property.
            IDictionary <string, OpenApiSchema> properties = new Dictionary <string, OpenApiSchema>();

            // structure properties
            foreach (var property in structuredType.StructuralProperties())
            {
                // OpenApiSchema propertySchema = property.Type.CreateSchema();
                // propertySchema.Default = property.DefaultValueString != null ? new OpenApiString(property.DefaultValueString) : null;
                if (property.Type.FullName() != structuredType.FullTypeName() &&
                    property.Type.FullName() != $"Collection({structuredType.FullTypeName()})")
                {
                    properties.Add(property.Name, context.CreatePropertySchema(property));
                }
            }

            // navigation properties
            foreach (var property in structuredType.NavigationProperties())
            {
                if (property.Type.FullName() != structuredType.FullTypeName() &&
                    property.Type.FullName() != $"Collection({structuredType.FullTypeName()})")
                {
                    OpenApiSchema propertySchema = context.CreateEdmTypeSchema(property.Type);
                    properties.Add(property.Name, propertySchema);
                }
            }

            return(properties);
        }
        public void CreateEdmTypeSchemaReturnSchemaForGuid(bool isNullable)
        {
            // Arrange
            IEdmModel         model            = EdmCoreModel.Instance;
            ODataContext      context          = new ODataContext(model);
            IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetGuid(isNullable);

            // Act
            var schema = context.CreateEdmTypeSchema(edmTypeReference);

            Assert.NotNull(schema); // guard
            string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);

            // & Assert
            if (isNullable)
            {
                Assert.Equal(@"{
  ""pattern"": ""^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"",
  ""type"": ""string"",
  ""format"": ""uuid"",
  ""nullable"": true
}".ChangeLineBreaks(), json);
            }
            else
            {
                Assert.Equal(@"{
  ""pattern"": ""^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"",
  ""type"": ""string"",
  ""format"": ""uuid""
}".ChangeLineBreaks(), json);
            }
        }
        public void CreateEdmTypeSchemaThrowArgumentNullEdmTypeReference()
        {
            // Arrange
            ODataContext context = new ODataContext(EdmCoreModel.Instance);

            // Act & Assert
            Assert.Throws <ArgumentNullException>("edmTypeReference", () => context.CreateEdmTypeSchema(edmTypeReference: null));
        }
        public void CreateEdmTypeSchemaThrowArgumentNullContext()
        {
            // Arrange
            ODataContext context = null;

            // Act & Assert
            Assert.Throws <ArgumentNullException>("context", () => context.CreateEdmTypeSchema(edmTypeReference: null));
        }
        public void CreateEdmTypeSchemaReturnSchemaForEnumType(bool isNullable, OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel    model    = EdmModelHelper.TripServiceModel;
            IEdmEnumType enumType = model.SchemaElements.OfType <IEdmEnumType>().First(c => c.Name == "PersonGender");

            Assert.NotNull(enumType); // guard
            IEdmEnumTypeReference enumTypeReference = new EdmEnumTypeReference(enumType, isNullable);
            ODataContext          context           = new ODataContext(model);

            context.Settings.OpenApiSpecVersion = specVersion;

            // Act
            var schema = context.CreateEdmTypeSchema(enumTypeReference);

            // & Assert
            Assert.NotNull(schema);


            if (specVersion == OpenApiSpecVersion.OpenApi2_0)
            {
                Assert.NotNull(schema.Reference);
                Assert.Null(schema.AnyOf);
                Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
                Assert.Equal(enumType.FullTypeName(), schema.Reference.Id);
                Assert.Equal(isNullable, schema.Nullable);
            }
            else
            {
                if (isNullable)
                {
                    Assert.NotNull(schema.AnyOf);
                    Assert.NotEmpty(schema.AnyOf);
                    Assert.Null(schema.Reference);
                    Assert.Equal(2, schema.AnyOf.Count);
                    var anyOfRef = schema.AnyOf.FirstOrDefault();
                    Assert.NotNull(anyOfRef.Reference);
                    Assert.Equal(ReferenceType.Schema, anyOfRef.Reference.Type);
                    Assert.Equal(enumType.FullTypeName(), anyOfRef.Reference.Id);
                    var anyOfNull = schema.AnyOf.Skip(1).FirstOrDefault();
                    Assert.NotNull(anyOfNull.Type);
                    Assert.Equal("object", anyOfNull.Type);
                    Assert.True(anyOfNull.Nullable);
                }
                else
                {
                    Assert.Null(schema.AnyOf);
                    Assert.NotNull(schema.Reference);
                    Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
                    Assert.Equal(enumType.FullTypeName(), schema.Reference.Id);
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// Create the list of <see cref="OpenApiParameter"/> for a <see cref="IEdmFunction"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="function">The Edm function.</param>
        /// <param name="parameterNameMapping">The parameter name mapping.</param>
        /// <returns>The created list of <see cref="OpenApiParameter"/>.</returns>
        public static IList <OpenApiParameter> CreateParameters(this ODataContext context, IEdmFunction function,
                                                                IDictionary <string, string> parameterNameMapping = null)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(function, nameof(function));

            IList <OpenApiParameter> parameters = new List <OpenApiParameter>();
            int skip = function.IsBound ? 1 : 0;

            foreach (IEdmOperationParameter edmParameter in function.Parameters.Skip(skip))
            {
                // Structured or collection-valued parameters are represented as a parameter alias
                // in the path template and the parameters array contains a Parameter Object for
                // the parameter alias as a query option of type string.
                if (edmParameter.Type.IsStructured() ||
                    edmParameter.Type.IsCollection())
                {
                    parameters.Add(new OpenApiParameter
                    {
                        Name     = parameterNameMapping == null ? edmParameter.Name : parameterNameMapping[edmParameter.Name],
                        In       = ParameterLocation.Query, // as query option
                        Required = true,
                        Schema   = new OpenApiSchema
                        {
                            Type = "string",

                            // These Parameter Objects optionally can contain the field description,
                            // whose value is the value of the unqualified annotation Core.Description of the parameter.
                            Description = context.Model.GetDescriptionAnnotation(edmParameter)
                        },

                        // The parameter description describes the format this URL-encoded JSON object or array, and/or reference to [OData-URL].
                        Description = "The URL-encoded JSON " + (edmParameter.Type.IsStructured() ? "array" : "object")
                    });
                }
                else
                {
                    // Primitive parameters use the same type mapping as described for primitive properties.
                    parameters.Add(new OpenApiParameter
                    {
                        Name     = parameterNameMapping == null ? edmParameter.Name : parameterNameMapping[edmParameter.Name],
                        In       = ParameterLocation.Path,
                        Required = true,
                        Schema   = context.CreateEdmTypeSchema(edmParameter.Type)
                    });
                }
            }

            return(parameters);
        }
        /// <summary>
        /// Create a <see cref="OpenApiRequestBody"/> for a <see cref="IEdmAction"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="action">The Edm action.</param>
        /// <returns>The created <see cref="OpenApiRequestBody"/> or null.</returns>
        public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmAction action)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(action, nameof(action));

            // return null for empty action parameters
            int skip = 0;

            if (action.IsBound)
            {
                if (action.Parameters.Count() <= 1)
                {
                    return(null);
                }
                skip = 1; //skip the binding parameter
            }
            else
            {
                if (!action.Parameters.Any())
                {
                    return(null);
                }
            }

            OpenApiSchema parametersSchema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>()
            };

            foreach (var parameter in action.Parameters.Skip(skip))
            {
                parametersSchema.Properties.Add(parameter.Name, context.CreateEdmTypeSchema(parameter.Type));
            }

            OpenApiRequestBody requestBody = new OpenApiRequestBody
            {
                Description = "Action parameters",
                Required    = true,
                Content     = new Dictionary <string, OpenApiMediaType>()
            };

            requestBody.Content.Add(Constants.ApplicationJsonMediaType, new OpenApiMediaType
            {
                Schema = parametersSchema
            });

            return(requestBody);
        }
        /// <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()));
            }
        }
        /// <summary>
        /// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmProperty"/>.
        /// Each structural property and navigation property is represented as a name/value pair of the
        /// standard OpenAPI properties object. The name is the property name,
        /// the value is a Schema Object describing the allowed values of the property.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="property">The Edm property.</param>
        /// <returns>The created <see cref="OpenApiSchema"/>.</returns>
        public static OpenApiSchema CreatePropertySchema(this ODataContext context, IEdmProperty property)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(property, nameof(property));

            OpenApiSchema schema = context.CreateEdmTypeSchema(property.Type);

            switch (property.PropertyKind)
            {
            case EdmPropertyKind.Structural:
                IEdmStructuralProperty structuralProperty = (IEdmStructuralProperty)property;
                schema.Default = CreateDefault(structuralProperty);
                break;
            }

            // The Schema Object for a property optionally can contain the field description,
            // whose value is the value of the unqualified annotation Core.Description of the property.
            schema.Description = context.Model.GetDescriptionAnnotation(property);

            return(schema);
        }
        public void CreateEdmTypeSchemaReturnSchemaForEnumType(bool isNullable, OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel    model    = EdmModelHelper.TripServiceModel;
            IEdmEnumType enumType = model.SchemaElements.OfType <IEdmEnumType>().First(c => c.Name == "PersonGender");

            Assert.NotNull(enumType); // guard
            IEdmEnumTypeReference enumTypeReference = new EdmEnumTypeReference(enumType, isNullable);
            ODataContext          context           = new ODataContext(model);

            context.Settings.OpenApiSpecVersion = specVersion;

            // Act
            var schema = context.CreateEdmTypeSchema(enumTypeReference);

            // & Assert
            Assert.NotNull(schema);

            // Although the schema will be set
            // for openApiV2 nullable will not be serialized
            Assert.Equal(isNullable, schema.Nullable);

            if (specVersion == OpenApiSpecVersion.OpenApi2_0)
            {
                Assert.NotNull(schema.Reference);
                Assert.Null(schema.AnyOf);
                Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
                Assert.Equal(enumType.FullTypeName(), schema.Reference.Id);
            }
            else
            {
                Assert.Null(schema.Reference);
                Assert.NotNull(schema.AnyOf);
                Assert.NotEmpty(schema.AnyOf);
                var anyOf = Assert.Single(schema.AnyOf);
                Assert.NotNull(anyOf.Reference);
                Assert.Equal(ReferenceType.Schema, anyOf.Reference.Type);
                Assert.Equal(enumType.FullTypeName(), anyOf.Reference.Id);
            }
        }
        public void CreateEdmTypeSchemaReturnSchemaForNonNullableCollectionPrimitiveType()
        {
            // Arrange
            IEdmModel    model   = EdmCoreModel.Instance;
            ODataContext context = new ODataContext(model);
            IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
                new EdmCollectionType(EdmCoreModel.Instance.GetString(false)));

            // Act
            var schema = context.CreateEdmTypeSchema(collectionType);

            Assert.NotNull(schema);
            string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);

            // & Assert
            Assert.Equal(@"{
  ""type"": ""array"",
  ""items"": {
    ""type"": ""string""
  }
}".ChangeLineBreaks(), json);
        }
        public void CreateEdmTypeSchemaReturnSchemaForSingle(bool isNullable)
        {
            // Arrange
            IEdmModel         model            = EdmCoreModel.Instance;
            ODataContext      context          = new ODataContext(model);
            IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetSingle(isNullable);

            // Act
            var schema = context.CreateEdmTypeSchema(edmTypeReference);

            Assert.NotNull(schema); // guard

            // & Assert
            Assert.Null(schema.Type);

            Assert.Equal("float", schema.Format);
            Assert.Equal(isNullable, schema.Nullable);

            Assert.Null(schema.OneOf);

            Assert.NotNull(schema.AnyOf);
            Assert.Equal(3, schema.AnyOf.Count);
        }
        public void CreateEdmTypeSchemaReturnSchemaForComplexType(bool isNullable, OpenApiSpecVersion specVersion)
        {
            // Arrange
            IEdmModel       model   = EdmModelHelper.TripServiceModel;
            IEdmComplexType complex = model.SchemaElements.OfType <IEdmComplexType>().First(c => c.Name == "AirportLocation");

            Assert.NotNull(complex); // guard
            IEdmComplexTypeReference complexTypeReference = new EdmComplexTypeReference(complex, isNullable);
            ODataContext             context = new ODataContext(model);

            context.Settings.OpenApiSpecVersion = specVersion;

            // Act
            var schema = context.CreateEdmTypeSchema(complexTypeReference);

            // & Assert
            Assert.NotNull(schema);

            if (specVersion == OpenApiSpecVersion.OpenApi2_0 || isNullable == false)
            {
                Assert.Null(schema.AnyOf);
                Assert.NotNull(schema.Reference);
                Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
                Assert.Equal(complex.FullTypeName(), schema.Reference.Id);
            }
            else
            {
                Assert.Null(schema.Reference);
                Assert.NotNull(schema.AnyOf);
                Assert.NotEmpty(schema.AnyOf);
                Assert.Equal(2, schema.AnyOf.Count);
                var anyOf = schema.AnyOf.FirstOrDefault();
                Assert.NotNull(anyOf.Reference);
                Assert.Equal(ReferenceType.Schema, anyOf.Reference.Type);
                Assert.Equal(complex.FullTypeName(), anyOf.Reference.Id);
            }
        }
        /// <summary>
        /// Create the list of <see cref="OpenApiParameter"/> for a <see cref="IEdmFunction"/>.
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="function">The Edm function.</param>
        /// <param name="parameterNameMapping">The parameter name mapping.</param>
        /// <returns>The created list of <see cref="OpenApiParameter"/>.</returns>
        public static IList <OpenApiParameter> CreateParameters(this ODataContext context, IEdmFunction function,
                                                                IDictionary <string, string> parameterNameMapping = null)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(function, nameof(function));

            IList <OpenApiParameter> parameters = new List <OpenApiParameter>();
            int skip = function.IsBound ? 1 : 0;

            foreach (IEdmOperationParameter edmParameter in function.Parameters.Skip(skip))
            {
                if (parameterNameMapping != null)
                {
                    if (!parameterNameMapping.ContainsKey(edmParameter.Name))
                    {
                        continue;
                    }
                }

                OpenApiParameter parameter;
                if (edmParameter.Type.IsStructured() ||
                    edmParameter.Type.IsCollection())
                {
                    parameter = new OpenApiParameter
                    {
                        Name     = parameterNameMapping == null ? edmParameter.Name : parameterNameMapping[edmParameter.Name],
                        In       = ParameterLocation.Path,
                        Required = true,

                        // Create schema in the Content property to indicate that the parameters are serialized as JSON
                        Content = new Dictionary <string, OpenApiMediaType>
                        {
                            {
                                Constants.ApplicationJsonMediaType,
                                new OpenApiMediaType
                                {
                                    Schema = new OpenApiSchema
                                    {
                                        Type  = "array",
                                        Items = new OpenApiSchema
                                        {
                                            Type = "string"
                                        },

                                        // These Parameter Objects optionally can contain the field description,
                                        // whose value is the value of the unqualified annotation Core.Description of the parameter.
                                        Description = context.Model.GetDescriptionAnnotation(edmParameter)
                                    }
                                }
                            }
                        },

                        // The parameter description describes the format this URL-encoded JSON object or array, and/or reference to [OData-URL].
                        Description = "The URL-encoded JSON " + (edmParameter.Type.IsStructured() ? "array" : "object")
                    };
                }
                else
                {
                    // Primitive parameters use the same type mapping as described for primitive properties.
                    bool isOptionalParameter = edmParameter is IEdmOptionalParameter;
                    parameter = new OpenApiParameter
                    {
                        Name     = parameterNameMapping == null ? edmParameter.Name : parameterNameMapping[edmParameter.Name],
                        In       = isOptionalParameter ? ParameterLocation.Query : ParameterLocation.Path,
                        Required = !isOptionalParameter,
                        Schema   = context.CreateEdmTypeSchema(edmParameter.Type)
                    };
                }

                if (parameterNameMapping != null)
                {
                    var quote = edmParameter.Type.Definition.ShouldPathParameterBeQuoted(context.Settings) ? "'" : string.Empty;
                    parameter.Description = $"Usage: {edmParameter.Name}={quote}{{{parameterNameMapping[edmParameter.Name]}}}{quote}";
                }

                parameters.Add(parameter);
            }

            return(parameters);
        }
Beispiel #24
0
        /// <summary>
        /// Create the <see cref="OpenApiResponses"/> for a <see cref="IEdmOperation"/>
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="operation">The Edm operation.</param>
        /// <param name="path">The OData path.</param>
        /// <returns>The created <see cref="OpenApiResponses"/>.</returns>
        public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation, ODataPath path)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(operation, nameof(operation));
            Utils.CheckArgumentNull(path, nameof(path));

            OpenApiResponses responses = new();

            if (operation.IsAction() && operation.ReturnType == null)
            {
                responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
            }
            else
            {
                OpenApiSchema schema;
                if (operation.ReturnType.IsCollection())
                {
                    // Get the entity type of the previous segment
                    IEdmEntityType entityType = path.Segments.Reverse().Skip(1)?.Take(1)?.FirstOrDefault()?.EntityType;
                    schema = new OpenApiSchema
                    {
                        Title      = entityType == null ? null : $"Collection of {entityType.Name}",
                        Type       = "object",
                        Properties = new Dictionary <string, OpenApiSchema>
                        {
                            {
                                "value", context.CreateEdmTypeSchema(operation.ReturnType)
                            }
                        }
                    };
                }
                else if (operation.ReturnType.IsPrimitive())
                {
                    // A property or operation response that is of a primitive type is represented as an object with a single name/value pair,
                    // whose name is value and whose value is a primitive value.
                    schema = new OpenApiSchema
                    {
                        Type       = "object",
                        Properties = new Dictionary <string, OpenApiSchema>
                        {
                            {
                                "value", context.CreateEdmTypeSchema(operation.ReturnType)
                            }
                        }
                    };
                }
                else
                {
                    schema = context.CreateEdmTypeSchema(operation.ReturnType);
                }

                string mediaType = Constants.ApplicationJsonMediaType;
                if (operation.ReturnType.AsPrimitive()?.PrimitiveKind() == EdmPrimitiveTypeKind.Stream)
                {
                    // Responses of types Edm.Stream should be application/octet-stream
                    mediaType = Constants.ApplicationOctetStreamMediaType;
                }

                OpenApiResponse response = new()
                {
                    Description = "Success",
                    Content     = new Dictionary <string, OpenApiMediaType>
                    {
                        {
                            mediaType,
                            new OpenApiMediaType
                            {
                                Schema = schema
                            }
                        }
                    }
                };
                responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response);
            }

            if (context.Settings.ErrorResponsesAsDefault)
            {
                responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
            }
            else
            {
                responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse());
                responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse());
            }

            return(responses);
        }