private OpenApiSchema GenerateInlineSchema(DataContract dataContract, SchemaRepository schemaRepository)
        {
            if (dataContract.DataType == DataType.Unknown)
            {
                return(new OpenApiSchema());
            }

            if (dataContract.DataType == DataType.Object)
            {
                return(GenerateObjectSchema(dataContract, schemaRepository));
            }

            if (dataContract.DataType == DataType.Array)
            {
                return(GenerateArraySchema(dataContract, schemaRepository));
            }

            else
            {
                return(GeneratePrimitiveSchema(dataContract));
            }
        }
        private OpenApiSchema GenerateSchemaForType(Type type, SchemaRepository schemaRepository)
        {
            if (TryGetCustomMapping(type, out var mapping))
            {
                return(mapping());
            }

            if (type.IsAssignableToOneOf(typeof(IFormFile), typeof(FileResult)))
            {
                return(new OpenApiSchema {
                    Type = "string", Format = "binary"
                });
            }

            if (_generatorOptions.GeneratePolymorphicSchemas)
            {
                var knownSubTypes = _generatorOptions.SubTypesResolver(type);
                if (knownSubTypes.Any())
                {
                    return(GeneratePolymorphicSchema(knownSubTypes, schemaRepository));
                }
            }

            var dataContract = _dataContractResolver.GetDataContractForType(type);

            var shouldBeReferenced =
                // regular object
                (dataContract.DataType == DataType.Object && dataContract.Properties != null && !dataContract.UnderlyingType.IsDictionary()) ||
                // dictionary-based AND self-referencing
                (dataContract.DataType == DataType.Object && dataContract.AdditionalPropertiesType == dataContract.UnderlyingType) ||
                // array-based AND self-referencing
                (dataContract.DataType == DataType.Array && dataContract.ArrayItemType == dataContract.UnderlyingType) ||
                // enum-based AND opted-out of inline
                (dataContract.EnumValues != null && !_generatorOptions.UseInlineDefinitionsForEnums);

            return((shouldBeReferenced)
                ? GenerateReferencedSchema(dataContract, schemaRepository)
                : GenerateInlineSchema(dataContract, schemaRepository));
        }
Example #3
0
        protected override OpenApiSchema GenerateDefinitionSchema(ApiModel apiModel, SchemaRepository schemaRepository)
        {
            var apiObject = (ApiObject)apiModel;

            var additionalProperties = (apiObject.AdditionalPropertiesType != null)
                ? Generator.GenerateSchema(apiObject.AdditionalPropertiesType, schemaRepository)
                : null;

            var schema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>(),
                Required   = new SortedSet <string>(),
                AdditionalPropertiesAllowed = (additionalProperties != null),
                AdditionalProperties        = additionalProperties
            };

            foreach (var apiProperty in apiObject.ApiProperties)
            {
                // For data annotations, support inline attributes (i.e. applied to member directly) OR attributes applied through a MetadataType
                var propertyAttributes = (apiProperty.MemberInfo is PropertyInfo propertyInfo)
                    ? propertyInfo.GetInlineOrMetadataTypeAttributes()
                    : Enumerable.Empty <object>();

                if (Options.IgnoreObsoleteProperties && propertyAttributes.OfType <ObsoleteAttribute>().Any())
                {
                    continue;
                }

                schema.Properties.Add(apiProperty.ApiName, GeneratePropertySchema(apiProperty, propertyAttributes, schemaRepository));

                if (apiProperty.ApiRequired || propertyAttributes.OfType <RequiredAttribute>().Any())
                {
                    schema.Required.Add(apiProperty.ApiName);
                }
            }

            return(schema);
        }
Example #4
0
        private OpenApiRequestBody GenerateRequestBody(
            ApiDescription apiDescription,
            SchemaRepository schemaRepository)
        {
            var bodyParameter = apiDescription.ParameterDescriptions
                                .FirstOrDefault(paramDesc => paramDesc.IsFromBody());

            if (bodyParameter != null)
            {
                return(GenerateRequestBodyFromBodyParameter(apiDescription, schemaRepository, bodyParameter));
            }

            var formParameters = apiDescription.ParameterDescriptions
                                 .Where(paramDesc => paramDesc.IsFromForm());

            if (formParameters.Any())
            {
                return(GenerateRequestBodyFromFormParameters(apiDescription, schemaRepository, formParameters));
            }

            return(null);
        }
        private OpenApiMediaType GenerateRequestMediaType(
            string contentType,
            ApiDescription apiDescription,
            SchemaRepository schemaRepository)
        {
            // If there's form parameters, generate the form-flavoured media type
            var apiParametersFromForm = apiDescription.ParameterDescriptions
                                        .Where(paramDesc => paramDesc.IsFromForm());

            if (apiParametersFromForm.Any())
            {
                var schema = GenerateSchemaFromApiParameters(apiDescription, apiParametersFromForm, schemaRepository);

                // Provide schema and corresponding encoding map to specify "form" serialization style for all properties
                // This indicates that array properties must be submitted as multiple parameters with the same name.
                // NOTE: the swagger-ui doesn't currently support arrays of files - https://github.com/swagger-api/swagger-ui/issues/4600
                // NOTE: the swagger-ui doesn't currently honor encoding metadata - https://github.com/swagger-api/swagger-ui/issues/4836

                return(new OpenApiMediaType
                {
                    Schema = schema,
                    Encoding = schema.Properties.ToDictionary(
                        entry => entry.Key,
                        entry => new OpenApiEncoding {
                        Style = ParameterStyle.Form
                    }
                        )
                });
            }

            // Otherwise, generate a regular media type
            var apiParameterFromBody = apiDescription.ParameterDescriptions
                                       .First(paramDesc => paramDesc.IsFromBody());

            return(new OpenApiMediaType
            {
                Schema = _schemaGenerator.GenerateSchema(apiParameterFromBody.Type, schemaRepository)
            });
        }
Example #6
0
 private OpenApiSchema GenerateDictionarySchema(DataContract dataContract, SchemaRepository schemaRepository)
 {
     if (dataContract.DictionaryKeys != null)
     {
         return(new OpenApiSchema
         {
             Type = "object",
             Properties = dataContract.DictionaryKeys.ToDictionary(
                 name => name,
                 name => GenerateSchema(dataContract.DictionaryValueType, schemaRepository))
         });
     }
     else
     {
         return(new OpenApiSchema
         {
             Type = "object",
             AdditionalPropertiesAllowed = true,
             AdditionalProperties = GenerateSchema(dataContract.DictionaryValueType, schemaRepository)
         });
     }
 }
Example #7
0
        private OpenApiOperation GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
        {
            var operation = new OpenApiOperation
            {
                Tags        = GenerateOperationTags(apiDescription),
                OperationId = _options.OperationIdSelector(apiDescription),
                Parameters  = GenerateParameters(apiDescription, schemaRepository),
                RequestBody = GenerateRequestBody(apiDescription, schemaRepository),
                Responses   = GenerateResponses(apiDescription, schemaRepository),
                Deprecated  = apiDescription.CustomAttributes().OfType <ObsoleteAttribute>().Any()
            };

            apiDescription.TryGetMethodInfo(out MethodInfo methodInfo);
            var filterContext = new OperationFilterContext(apiDescription, _schemaGenerator, schemaRepository, methodInfo);

            foreach (var filter in _options.OperationFilters)
            {
                filter.Apply(operation, filterContext);
            }

            return(operation);
        }
Example #8
0
        private OpenApiRequestBody GenerateRequestBodyFromBodyParameter(
            ApiDescription apiDescription,
            SchemaRepository schemaRepository,
            ApiParameterDescription bodyParameter)
        {
            var contentTypes = InferRequestContentTypes(apiDescription);

            var isRequired = bodyParameter.CustomAttributes().Any(attr => RequiredAttributeTypes.Contains(attr.GetType()));

            return(new OpenApiRequestBody
            {
                Content = contentTypes
                          .ToDictionary(
                    contentType => contentType,
                    contentType => new OpenApiMediaType
                {
                    Schema = _schemaGenerator.GenerateSchema(bodyParameter.ModelMetadata.ModelType, schemaRepository)
                }
                    ),
                Required = isRequired
            });
        }
        public OpenApiDocument GetSwagger(string documentName, string host = null, string basePath = null)
        {
            if (!_options.SwaggerDocs.TryGetValue(documentName, out OpenApiInfo info))
            {
                throw new UnknownSwaggerDocument(documentName, _options.SwaggerDocs.Select(d => d.Key));
            }

            var applicableApiDescriptions = _apiDescriptionsProvider.ApiDescriptionGroups.Items
                                            .SelectMany(group => group.Items)
                                            .Where(apiDesc => !(_options.IgnoreObsoleteActions && apiDesc.CustomAttributes().OfType <ObsoleteAttribute>().Any()))
                                            .Where(apiDesc => _options.DocInclusionPredicate(documentName, apiDesc));

            var schemaRepository = new SchemaRepository(documentName);

            var swaggerDoc = new OpenApiDocument
            {
                Info       = info,
                Servers    = GenerateServers(host, basePath),
                Paths      = GeneratePaths(applicableApiDescriptions, schemaRepository),
                Components = new OpenApiComponents
                {
                    Schemas         = schemaRepository.Schemas,
                    SecuritySchemes = new Dictionary <string, OpenApiSecurityScheme>(_options.SecuritySchemes)
                },
                SecurityRequirements = new List <OpenApiSecurityRequirement>(_options.SecurityRequirements)
            };

            var filterContext = new DocumentFilterContext(applicableApiDescriptions, _schemaGenerator, schemaRepository);

            foreach (var filter in _options.DocumentFilters)
            {
                filter.Apply(swaggerDoc, filterContext);
            }

            swaggerDoc.Components.Schemas = new SortedDictionary <string, OpenApiSchema>(swaggerDoc.Components.Schemas, _options.SchemaComparer);

            return(swaggerDoc);
        }
Example #10
0
        public override OpenApiSchema CreateDefinitionSchema(Type type, SchemaRepository schemaRepository)
        {
            var isNullable = type.IsNullable(out Type innerType);

            var enumType = isNullable
                ? innerType
                : type;

            //Test to determine if the serializer will treat as string or not
            var describeAsString = JsonSerializer.Serialize(enumType.GetEnumValues().GetValue(0), _serializerOptions).StartsWith("\"");

            var schema = describeAsString
                ? EnumTypeMap[typeof(string)]()
                : EnumTypeMap[enumType.GetEnumUnderlyingType()]();

            if (describeAsString)
            {
                schema.Enum = enumType.GetEnumValues()
                              .Cast <object>()
                              .Select(value =>
                {
                    var stringValue = JsonSerializer.Serialize(value, _serializerOptions).Replace("\"", string.Empty);
                    return(OpenApiAnyFactory.CreateFor(schema, stringValue));
                })
                              .ToList();
            }
            else
            {
                schema.Enum = enumType.GetEnumValues()
                              .Cast <object>()
                              .Select(value => OpenApiAnyFactory.CreateFor(schema, value))
                              .ToList();
            }

            schema.Nullable = isNullable;

            return(schema);
        }
Example #11
0
        private OpenApiRequestBody GenerateRequestBody(
            ApiDescription apiDescription,
            IEnumerable <object> methodAttributes,
            SchemaRepository schemaRepository)
        {
            var requestContentTypes = InferRequestContentTypes(apiDescription, methodAttributes);

            if (!requestContentTypes.Any())
            {
                return(null);
            }

            var bodyParameter = apiDescription.ParameterDescriptions
                                .FirstOrDefault(paramDesc => paramDesc.IsFromBody());

            bool isRequired = false;

            if (bodyParameter != null)
            {
                bodyParameter.GetAdditionalMetadata(
                    apiDescription,
                    out ParameterInfo parameterInfo,
                    out PropertyInfo propertyInfo,
                    out IEnumerable <object> parameterOrPropertyAttributes);

                isRequired = parameterOrPropertyAttributes.Any(attr => RequiredAttributeTypes.Contains(attr.GetType()));
            }

            return(new OpenApiRequestBody
            {
                Required = isRequired,
                Content = requestContentTypes
                          .ToDictionary(
                    contentType => contentType,
                    contentType => GenerateRequestMediaType(contentType, apiDescription, schemaRepository)
                    )
            });
        }
        private OpenApiOperation GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
        {
#if NET6_0_OR_GREATER
            var metadata          = apiDescription.ActionDescriptor?.EndpointMetadata;
            var existingOperation = metadata?.OfType <OpenApiOperation>().SingleOrDefault();
            if (existingOperation != null)
            {
                return(existingOperation);
            }
#endif
            try
            {
                var operation = new OpenApiOperation
                {
                    Tags        = GenerateOperationTags(apiDescription),
                    OperationId = _options.OperationIdSelector(apiDescription),
                    Parameters  = GenerateParameters(apiDescription, schemaRepository),
                    RequestBody = GenerateRequestBody(apiDescription, schemaRepository),
                    Responses   = GenerateResponses(apiDescription, schemaRepository),
                    Deprecated  = apiDescription.CustomAttributes().OfType <ObsoleteAttribute>().Any()
                };

                apiDescription.TryGetMethodInfo(out MethodInfo methodInfo);
                var filterContext = new OperationFilterContext(apiDescription, _schemaGenerator, schemaRepository, methodInfo);
                foreach (var filter in _options.OperationFilters)
                {
                    filter.Apply(operation, filterContext);
                }

                return(operation);
            }
            catch (Exception ex)
            {
                throw new SwaggerGeneratorException(
                          message: $"Failed to generate Operation for action - {apiDescription.ActionDescriptor.DisplayName}. See inner exception",
                          innerException: ex);
            }
        }
Example #13
0
        private OpenApiSchema GenerateSchemaFromFormParameters(
            IEnumerable <ApiParameterDescription> formParameters,
            SchemaRepository schemaRepository)
        {
            var properties            = new Dictionary <string, OpenApiSchema>();
            var requiredPropertyNames = new List <string>();

            foreach (var formParameter in formParameters)
            {
                var name = _options.DescribeAllParametersInCamelCase
                    ? formParameter.Name.ToCamelCase()
                    : formParameter.Name;

                var schema = (formParameter.ModelMetadata != null)
                    ? _schemaGenerator.GenerateSchema(
                    formParameter.ModelMetadata.ModelType,
                    schemaRepository,
                    formParameter.PropertyInfo(),
                    formParameter.ParameterInfo())
                    : new OpenApiSchema {
                    Type = "string"
                };

                properties.Add(name, schema);

                if (formParameter.IsFromPath() || formParameter.CustomAttributes().Any(attr => RequiredAttributeTypes.Contains(attr.GetType())))
                {
                    requiredPropertyNames.Add(name);
                }
            }

            return(new OpenApiSchema
            {
                Type = "object",
                Properties = properties,
                Required = new SortedSet <string>(requiredPropertyNames)
            });
        }
        private OpenApiOperation GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
        {
            apiDescription.GetAdditionalMetadata(out MethodInfo methodInfo, out IEnumerable <object> methodAttributes);

            var operation = new OpenApiOperation
            {
                Tags        = GenerateTags(apiDescription),
                OperationId = _options.OperationIdSelector(apiDescription),
                Parameters  = GenerateParameters(apiDescription, schemaRepository),
                RequestBody = GenerateRequestBody(apiDescription, methodAttributes, schemaRepository),
                Responses   = GenerateResponses(apiDescription, methodAttributes, schemaRepository),
                Deprecated  = methodAttributes.OfType <ObsoleteAttribute>().Any()
            };

            var filterContext = new OperationFilterContext(apiDescription, _schemaGenerator, schemaRepository, methodInfo);

            foreach (var filter in _options.OperationFilters)
            {
                filter.Apply(operation, filterContext);
            }

            return(operation);
        }
        private OpenApiSchema GenerateDictionarySchema(DataContract dataContract, SchemaRepository schemaRepository)
        {
            if (dataContract.DictionaryKeyType.IsEnum)
            {
                // This is a special case where we can include named properties based on the enum values
                return(new OpenApiSchema
                {
                    Type = "object",
                    Properties = dataContract.DictionaryKeyType.GetEnumNames()
                                 .ToDictionary(
                        name => name,
                        name => GenerateSchema(dataContract.DictionaryValueType, schemaRepository)
                        )
                });
            }

            return(new OpenApiSchema
            {
                Type = "object",
                AdditionalPropertiesAllowed = true,
                AdditionalProperties = GenerateSchema(dataContract.DictionaryValueType, schemaRepository)
            });
        }
        private OpenApiSchema GenerateSchemaFromApiParameters(
            ApiDescription apiDescription,
            IEnumerable <ApiParameterDescription> apiParameters,
            SchemaRepository schemaRepository)
        {
            // First, map to a data structure that captures the pertinent metadata
            var parametersMetadata = apiParameters
                                     .Select(paramDesc =>
            {
                paramDesc.GetAdditionalMetadata(
                    apiDescription,
                    out ParameterInfo parameterInfo,
                    out PropertyInfo propertyInfo,
                    out IEnumerable <object> parameterOrPropertyAttributes);

                var name       = _options.DescribeAllParametersInCamelCase ? paramDesc.Name.ToCamelCase() : paramDesc.Name;
                var isRequired = parameterOrPropertyAttributes.Any(attr => RequiredAttributeTypes.Contains(attr.GetType()));
                var schema     = _schemaGenerator.GenerateSchema(paramDesc.Type, schemaRepository);

                return(new
                {
                    Name = name,
                    IsRequired = isRequired,
                    Schema = schema
                });
            });

            return(new OpenApiSchema
            {
                Type = "object",
                Properties = parametersMetadata.ToDictionary(
                    metadata => metadata.Name,
                    metadata => metadata.Schema
                    ),
                Required = new SortedSet <string>(parametersMetadata.Where(m => m.IsRequired).Select(m => m.Name)),
            });
        }
        private OpenApiSchema GeneratePolymorphicSchema(DataContract dataContract, SchemaRepository schemaRepository, IEnumerable <Type> subTypes)
        {
            var schema = new OpenApiSchema
            {
                OneOf         = new List <OpenApiSchema>(),
                Discriminator = TryGetDiscriminatorName(dataContract, out string discriminatorName)
                    ? new OpenApiDiscriminator {
                    PropertyName = discriminatorName
                }
                    : null
            };

            var subTypesDataContracts = subTypes
                                        .Select(subType => _serializerDataContractResolver.GetDataContractForType(subType));

            var allowedDataContracts = dataContract.UnderlyingType.IsAbstract
                ? subTypesDataContracts
                : new[] { dataContract }.Union(subTypesDataContracts);

            foreach (var allowedDataContract in allowedDataContracts)
            {
                var allowedSchema = GenerateReferencedSchema(
                    allowedDataContract.UnderlyingType,
                    schemaRepository,
                    () => GenerateObjectSchema(allowedDataContract, schemaRepository));

                schema.OneOf.Add(allowedSchema);

                if (schema.Discriminator != null && TryGetDiscriminatorValue(allowedDataContract, out string discriminatorValue))
                {
                    schema.Discriminator.Mapping.Add(discriminatorValue, allowedSchema.Reference.ReferenceV3);
                }
            }

            return(schema);
        }
Example #18
0
        public override OpenApiSchema CreateDefinitionSchema(Type type, SchemaRepository schemaRepository)
        {
            if (!type.IsDictionary(out Type keyType, out Type valueType))
            {
                throw new InvalidOperationException($"Type {type} is not a dictionary");
            }

            OpenApiSchema schema;

            if (keyType.IsEnum)
            {
                // This is a special case where we can include named properties based on the enum values
                schema = new OpenApiSchema
                {
                    Type       = "object",
                    Properties = keyType.GetEnumNames()
                                 .ToDictionary(
                        name => name,
                        name => _schemaGenerator.GenerateSchema(valueType, schemaRepository)
                        )
                };
            }
            else
            {
                schema = new OpenApiSchema
                {
                    Type = "object",
                    AdditionalPropertiesAllowed = true,
                    AdditionalProperties        = _schemaGenerator.GenerateSchema(valueType, schemaRepository)
                };
            }

            schema.Nullable = !_serializerOptions.IgnoreNullValues;

            return(schema);
        }
        private OpenApiSchema GenerateInlineSchema(DataContract dataContract, SchemaRepository schemaRepository)
        {
            if (dataContract.IsPrimitive)
            {
                return(GeneratePrimitiveSchema(dataContract));
            }

            if (dataContract.IsDictionary)
            {
                return(GenerateDictionarySchema(dataContract, schemaRepository));
            }

            if (dataContract.IsArray)
            {
                return(GenerateArraySchema(dataContract, schemaRepository));
            }

            if (dataContract.IsObject)
            {
                return(GenerateObjectSchema(dataContract, schemaRepository));
            }

            return(new OpenApiSchema());
        }
Example #20
0
 private OpenApiSchema CreateDictionarySchema(DataContract dataContract, SchemaRepository schemaRepository)
 {
     if (dataContract.DictionaryKeys != null)
     {
         // This is a special case where the set of key values is known (e.g. if the key type is an enum)
         return(new OpenApiSchema
         {
             Type = "object",
             Properties = dataContract.DictionaryKeys.ToDictionary(
                 name => name,
                 name => GenerateSchema(dataContract.DictionaryValueType, schemaRepository)),
             AdditionalPropertiesAllowed = false,
         });
     }
     else
     {
         return(new OpenApiSchema
         {
             Type = "object",
             AdditionalPropertiesAllowed = true,
             AdditionalProperties = GenerateSchema(dataContract.DictionaryValueType, schemaRepository)
         });
     }
 }
        public OpenApiDocument GetSwagger(string documentName, string host = null, string basePath = null)
        {
            if (!_options.SwaggerDocs.TryGetValue(documentName, out OpenApiInfo info))
            {
                throw new UnknownSwaggerDocument(documentName, _options.SwaggerDocs.Select(d => d.Key));
            }

            var applicableApiDescriptions = _apiDescriptionsProvider.ApiDescriptionGroups.Items
                                            .SelectMany(group => group.Items)
                                            .Where(apiDesc => _options.DocInclusionPredicate(documentName, apiDesc))
                                            .Where(apiDesc => !_options.IgnoreObsoleteActions || !apiDesc.IsObsolete());

            var schemaRepository = new SchemaRepository();

            var swaggerDoc = new OpenApiDocument
            {
                Info       = info,
                Servers    = GenerateServers(host, basePath),
                Paths      = GeneratePaths(applicableApiDescriptions, schemaRepository),
                Components = new OpenApiComponents
                {
                    Schemas         = schemaRepository.Schemas,
                    SecuritySchemes = _options.SecuritySchemes
                },
                SecurityRequirements = _options.SecurityRequirements
            };

            var filterContext = new DocumentFilterContext(applicableApiDescriptions, _schemaGenerator, schemaRepository);

            foreach (var filter in _options.DocumentFilters)
            {
                filter.Apply(swaggerDoc, filterContext);
            }

            return(swaggerDoc);
        }
Example #22
0
        private bool TryGetDiscriminatorFor(
            DataContract dataContract,
            SchemaRepository schemaRepository,
            IEnumerable <DataContract> knownTypesDataContracts,
            out OpenApiDiscriminator discriminator)
        {
            discriminator = null;

            var discriminatorName = _generatorOptions.DiscriminatorNameSelector(dataContract.UnderlyingType)
                                    ?? dataContract.ObjectTypeNameProperty;

            if (discriminatorName == null)
            {
                return(false);
            }

            discriminator = new OpenApiDiscriminator
            {
                PropertyName = discriminatorName
            };

            foreach (var knownTypeDataContract in knownTypesDataContracts)
            {
                var discriminatorValue = _generatorOptions.DiscriminatorValueSelector(knownTypeDataContract.UnderlyingType)
                                         ?? knownTypeDataContract.ObjectTypeNameValue;

                if (discriminatorValue == null)
                {
                    continue;
                }

                discriminator.Mapping.Add(discriminatorValue, GenerateConcreteSchema(knownTypeDataContract, schemaRepository).Reference.ReferenceV3);
            }

            return(true);
        }
        public OpenApiSchema GenerateSchema(
            Type type,
            SchemaRepository schemaRepository,
            MemberInfo memberInfo       = null,
            ParameterInfo parameterInfo = null)
        {
            var schema = GenerateSchemaForType(type, schemaRepository);

            if (memberInfo != null)
            {
                ApplyMemberMetadata(schema, type, memberInfo);
            }
            else if (parameterInfo != null)
            {
                ApplyParameterMetadata(schema, type, parameterInfo);
            }

            if (schema.Reference == null)
            {
                ApplyFilters(schema, type, schemaRepository, memberInfo, parameterInfo);
            }

            return(schema);
        }
 private OpenApiSchema GenerateReferencedSchema(SerializerMetadata serializerMetadata, SchemaRepository schemaRepository)
 {
     return(schemaRepository.GetOrAdd(
                serializerMetadata.Type,
                _generatorOptions.SchemaIdSelector(serializerMetadata.Type),
                () =>
     {
         var schema = GenerateInlineSchema(serializerMetadata, schemaRepository);
         ApplyFilters(schema, serializerMetadata.Type, schemaRepository);
         return schema;
     }));
 }
 private OpenApiSchema GeneratePolymorphicSchema(IEnumerable <Type> knownSubTypes, SchemaRepository schemaRepository)
 {
     return(new OpenApiSchema
     {
         OneOf = knownSubTypes
                 .Select(subType => GenerateSchema(subType, schemaRepository))
                 .ToList()
     });
 }
        private OpenApiSchema GenerateObjectSchema(SerializerMetadata serializerMetadata, SchemaRepository schemaRepository)
        {
            if (serializerMetadata.Properties == null)
            {
                return(new OpenApiSchema {
                    Type = "object"
                });
            }

            var schema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>(),
                Required   = new SortedSet <string>()
            };

            // If it's a baseType with known subTypes, add the discriminator property
            if (_generatorOptions.GeneratePolymorphicSchemas && _generatorOptions.SubTypesResolver(serializerMetadata.Type).Any())
            {
                var discriminatorName = _generatorOptions.DiscriminatorSelector(serializerMetadata.Type);

                if (!schema.Properties.ContainsKey(discriminatorName))
                {
                    schema.Properties.Add(discriminatorName, new OpenApiSchema {
                        Type = "string"
                    });
                }

                schema.Required.Add(discriminatorName);
                schema.Discriminator = new OpenApiDiscriminator {
                    PropertyName = discriminatorName
                };
            }

            foreach (var serializerPropertyMetadata in serializerMetadata.Properties)
            {
                var customAttributes = serializerPropertyMetadata.MemberInfo?.GetInlineOrMetadataTypeAttributes() ?? Enumerable.Empty <object>();

                if (_generatorOptions.IgnoreObsoleteProperties && customAttributes.OfType <ObsoleteAttribute>().Any())
                {
                    continue;
                }

                var propertySchema = GenerateSchema(serializerPropertyMetadata.MemberType, schemaRepository, memberInfo: serializerPropertyMetadata.MemberInfo);

                schema.Properties.Add(serializerPropertyMetadata.Name, propertySchema);

                if (serializerPropertyMetadata.IsRequired || customAttributes.OfType <RequiredAttribute>().Any())
                {
                    schema.Required.Add(serializerPropertyMetadata.Name);
                }

                if (propertySchema.Reference == null)
                {
                    propertySchema.Nullable = propertySchema.Nullable && serializerPropertyMetadata.AllowNull;
                }
            }

            if (serializerMetadata.ExtensionDataValueType != null)
            {
                schema.AdditionalProperties = GenerateSchema(serializerMetadata.ExtensionDataValueType, schemaRepository);
            }

            // If it's a known subType, reference the baseType for inheritied properties
            if (_generatorOptions.GeneratePolymorphicSchemas &&
                (serializerMetadata.Type.BaseType != null) &&
                _generatorOptions.SubTypesResolver(serializerMetadata.Type.BaseType).Contains(serializerMetadata.Type))
            {
                var baseSerializerContract = _serializerMetadataResolver.GetSerializerMetadataForType(serializerMetadata.Type.BaseType);
                var baseSchemaReference    = GenerateReferencedSchema(baseSerializerContract, schemaRepository);

                var baseSchema = schemaRepository.Schemas[baseSchemaReference.Reference.Id];
                foreach (var basePropertyName in baseSchema.Properties.Keys)
                {
                    schema.Properties.Remove(basePropertyName);
                }

                return(new OpenApiSchema
                {
                    AllOf = new List <OpenApiSchema> {
                        baseSchemaReference, schema
                    }
                });
            }

            return(schema);
        }
 private OpenApiSchema GenerateArraySchema(SerializerMetadata serializerMetadata, SchemaRepository schemaRepository)
 {
     return(new OpenApiSchema
     {
         Type = "array",
         Items = GenerateSchema(serializerMetadata.ArrayItemType, schemaRepository),
         UniqueItems = serializerMetadata.Type.IsSet() ? (bool?)true : null
     });
 }
        private OpenApiSchema GenerateInlineSchema(SerializerMetadata serializerMetadata, SchemaRepository schemaRepository)
        {
            if (serializerMetadata.IsPrimitive)
            {
                return(GeneratePrimitiveSchema(serializerMetadata));
            }

            if (serializerMetadata.IsDictionary)
            {
                return(GenerateDictionarySchema(serializerMetadata, schemaRepository));
            }

            if (serializerMetadata.IsArray)
            {
                return(GenerateArraySchema(serializerMetadata, schemaRepository));
            }

            if (serializerMetadata.IsObject)
            {
                return(GenerateObjectSchema(serializerMetadata, schemaRepository));
            }

            return(new OpenApiSchema());
        }
Example #29
0
        private OpenApiSchema GeneratePropertySchema(
            JsonProperty jsonProperty,
            MemberInfo memberInfo,
            object[] attributes,
            SchemaRepository schemaRepository)
        {
            var schema = RootGenerator.GenerateSchema(jsonProperty.PropertyType, schemaRepository);

            schema.WriteOnly = jsonProperty.Writable && !jsonProperty.Readable;
            schema.ReadOnly  = jsonProperty.Readable && !jsonProperty.Writable;

            foreach (var attribute in attributes)
            {
                if (attribute is DefaultValueAttribute defaultValue)
                {
                    schema.Default = OpenApiAnyFactory.TryCreateFor(schema, defaultValue.Value, out IOpenApiAny openApiAny)
                        ? openApiAny
                        : schema.Default;
                }
                else if (attribute is RegularExpressionAttribute regex)
                {
                    schema.Pattern = regex.Pattern;
                }
                else if (attribute is RangeAttribute range)
                {
                    schema.Maximum = decimal.TryParse(range.Maximum.ToString(), out decimal maximum)
                        ? maximum
                        : schema.Maximum;

                    schema.Minimum = decimal.TryParse(range.Minimum.ToString(), out decimal minimum)
                        ? minimum
                        : schema.Minimum;
                }
                else if (attribute is MinLengthAttribute minLength)
                {
                    schema.MinLength = minLength.Length;
                }
                else if (attribute is MaxLengthAttribute maxLength)
                {
                    schema.MaxLength = maxLength.Length;
                }
                else if (attribute is StringLengthAttribute stringLength)
                {
                    schema.MinLength = stringLength.MinimumLength;
                    schema.MaxLength = stringLength.MaximumLength;
                }
                else if (attribute is EmailAddressAttribute)
                {
                    schema.Format = "email";
                }
                else if (attribute is CreditCardAttribute)
                {
                    schema.Format = "credit-card";
                }
                else if (attribute is PhoneAttribute)
                {
                    schema.Format = "tel";
                }
                else if (attribute is DataTypeAttribute dataTypeAttribute && schema.Type == "string")
                {
                    schema.Format = DataTypeFormatMap.TryGetValue(dataTypeAttribute.DataType, out string format)
                        ? format
                        : schema.Format;
                }
            }

            return(schema);
        }
Example #30
0
 public abstract OpenApiSchema CreateDefinitionSchema(Type type, SchemaRepository schemaRepository);