/// <summary> /// Converts <see cref="Type"/> to <see cref="OpenApiSchema"/>. /// </summary> /// <param name="type"><see cref="Type"/> instance.</param> /// <param name="namingStrategy"><see cref="NamingStrategy"/> insance to create the JSON schema from .NET Types.</param> /// <param name="attribute"><see cref="OpenApiSchemaVisibilityAttribute"/> instance. Default is <c>null</c>.</param> /// <returns><see cref="OpenApiSchema"/> instance.</returns> /// <remarks> /// It runs recursively to build the entire object type. It only takes properties without <see cref="JsonIgnoreAttribute"/>. /// </remarks> public static OpenApiSchema ToOpenApiSchema(this Type type, NamingStrategy namingStrategy, OpenApiSchemaVisibilityAttribute attribute = null) { type.ThrowIfNullOrDefault(); var schema = (OpenApiSchema)null; if (type == typeof(JObject)) { schema = typeof(object).ToOpenApiSchema(namingStrategy); return(schema); } if (type == typeof(JToken)) { schema = typeof(object).ToOpenApiSchema(namingStrategy); return(schema); } var unwrappedValueType = Nullable.GetUnderlyingType(type); if (!unwrappedValueType.IsNullOrDefault()) { schema = unwrappedValueType.ToOpenApiSchema(namingStrategy); schema.Nullable = true; return(schema); } schema = new OpenApiSchema() { Type = type.ToDataType(), Format = type.ToDataFormat() }; if (!attribute.IsNullOrDefault()) { var visibility = new OpenApiString(attribute.Visibility.ToDisplayName()); schema.Extensions.Add("x-ms-visibility", visibility); } if (typeof(Enum).IsAssignableFrom(type)) { var isFlags = type.IsDefined(typeof(FlagsAttribute), false); if (!isFlags) { var converterAttribute = type.GetCustomAttribute <JsonConverterAttribute>(); if (!converterAttribute.IsNullOrDefault() && typeof(StringEnumConverter).IsAssignableFrom(converterAttribute.ConverterType)) { var names = Enum.GetNames(type); schema.Enum = names.Select(p => (IOpenApiAny) new OpenApiString(namingStrategy.GetPropertyName(p, false))).ToList(); schema.Type = "string"; schema.Format = null; } else if (type.GetEnumUnderlyingType() == typeof(short)) { var values = Enum.GetValues(type); schema.Enum = values.Cast <short>().Select(p => (IOpenApiAny) new OpenApiInteger(p)).ToList(); } else if (type.GetEnumUnderlyingType() == typeof(int)) { var values = Enum.GetValues(type); schema.Enum = values.Cast <int>().Select(p => (IOpenApiAny) new OpenApiInteger(p)).ToList(); } else if (type.GetEnumUnderlyingType() == typeof(long)) { var values = Enum.GetValues(type); schema.Enum = values.Cast <long>().Select(p => (IOpenApiAny) new OpenApiLong(p)).ToList(); } } } if (type.IsSimpleType()) { return(schema); } if (typeof(IDictionary).IsAssignableFrom(type)) { schema.AdditionalProperties = type.GetGenericArguments()[1].ToOpenApiSchema(namingStrategy); return(schema); } if (type.IsOpenApiArray()) { schema.Type = "array"; schema.Items = (type.GetElementType() ?? type.GetGenericArguments()[0]).ToOpenApiSchema(namingStrategy); return(schema); } var properties = type.GetProperties().Where(p => !p.ExistsCustomAttribute <JsonIgnoreAttribute>()); foreach (var property in properties) { var visiblity = property.GetCustomAttribute <OpenApiSchemaVisibilityAttribute>(inherit: false); var propertyName = property.GetJsonPropertyName(); schema.Properties[namingStrategy.GetPropertyName(property.Name, false)] = property.PropertyType.ToOpenApiSchema(namingStrategy, visiblity); } return(schema); }
/// <summary> /// Converts <see cref="Type"/> to <see cref="OpenApiSchema"/>. /// </summary> /// <param name="type"><see cref="Type"/> instance.</param> /// <param name="namingStrategy"><see cref="NamingStrategy"/> instance to create the JSON schema from .NET Types.</param> /// <param name="attribute"><see cref="OpenApiSchemaVisibilityAttribute"/> instance. Default is <c>null</c>.</param> /// <returns><see cref="OpenApiSchema"/> instance.</returns> /// <remarks> /// It runs recursively to build the entire object type. It only takes properties without <see cref="JsonIgnoreAttribute"/>. /// </remarks> public static OpenApiSchema ToOpenApiSchema(this Type type, NamingStrategy namingStrategy, OpenApiSchemaVisibilityAttribute attribute = null) { type.ThrowIfNullOrDefault(); var schema = (OpenApiSchema)null; if (type.IsJObjectType()) { schema = typeof(object).ToOpenApiSchema(namingStrategy); return(schema); } var unwrappedValueType = Nullable.GetUnderlyingType(type); if (!unwrappedValueType.IsNullOrDefault()) { schema = unwrappedValueType.ToOpenApiSchema(namingStrategy); schema.Nullable = true; return(schema); } schema = new OpenApiSchema() { Type = type.ToDataType(), Format = type.ToDataFormat() }; if (!attribute.IsNullOrDefault()) { var visibility = new OpenApiString(attribute.Visibility.ToDisplayName()); schema.Extensions.Add("x-ms-visibility", visibility); } if (type.IsUnflaggedEnumType()) { var converterAttribute = type.GetCustomAttribute <JsonConverterAttribute>(); if (!converterAttribute.IsNullOrDefault() && typeof(StringEnumConverter).IsAssignableFrom(converterAttribute.ConverterType)) { schema.Type = "string"; schema.Format = null; schema.Enum = type.ToOpenApiStringCollection(namingStrategy); } else { schema.Enum = type.ToOpenApiIntegerCollection(); } } if (type.IsSimpleType()) { return(schema); } if (type.IsOpenApiDictionary()) { schema.AdditionalProperties = type.GetGenericArguments()[1].ToOpenApiSchema(namingStrategy); return(schema); } if (type.IsOpenApiArray()) { schema.Type = "array"; schema.Items = (type.GetElementType() ?? type.GetGenericArguments()[0]).ToOpenApiSchema(namingStrategy); return(schema); } var allProperties = type.IsInterface ? new[] { type }.Concat(type.GetInterfaces()).SelectMany(i => i.GetProperties()) : type.GetProperties(); var properties = allProperties.Where(p => !p.ExistsCustomAttribute <JsonIgnoreAttribute>()); foreach (var property in properties) { var visiblity = property.GetCustomAttribute <OpenApiSchemaVisibilityAttribute>(inherit: false); var propertyName = property.GetJsonPropertyName(); var ts = property.DeclaringType.GetGenericArguments(); if (!ts.Any()) { schema.Properties[namingStrategy.GetPropertyName(property.Name, false)] = property.PropertyType.ToOpenApiSchema(namingStrategy, visiblity); continue; } var reference = new OpenApiReference() { Type = ReferenceType.Schema, Id = property.PropertyType.GetOpenApiRootReferenceId() }; var referenceSchema = new OpenApiSchema() { Reference = reference }; if (!ts.Contains(property.PropertyType)) { if (property.PropertyType.IsOpenApiDictionary()) { reference.Id = property.PropertyType.GetOpenApiReferenceId(true, false); var dictionarySchema = new OpenApiSchema() { Type = "object", AdditionalProperties = referenceSchema }; schema.Properties[namingStrategy.GetPropertyName(property.Name, false)] = dictionarySchema; continue; } if (property.PropertyType.IsOpenApiArray()) { reference.Id = property.PropertyType.GetOpenApiReferenceId(false, true); var arraySchema = new OpenApiSchema() { Type = "array", Items = referenceSchema }; schema.Properties[namingStrategy.GetPropertyName(property.Name, false)] = arraySchema; continue; } schema.Properties[namingStrategy.GetPropertyName(property.Name, false)] = property.PropertyType.ToOpenApiSchema(namingStrategy, visiblity); continue; } schema.Properties[namingStrategy.GetPropertyName(property.Name, false)] = referenceSchema; } return(schema); }
/// <summary> /// Converts <see cref="Type"/> to <see cref="OpenApiSchema"/>. /// </summary> /// <param name="type"><see cref="Type"/> instance.</param> /// <param name="namingStrategy"><see cref="NamingStrategy"/> instance to create the JSON schema from .NET Types.</param> /// <param name="attribute"><see cref="OpenApiSchemaVisibilityAttribute"/> instance. Default is <c>null</c>.</param> /// <param name="returnSingleSchema">Value indicating whether to return single schema or not.</param> /// <param name="depth">Recurring depth.</param> /// <returns>Returns <see cref="Dictionary{String, OpenApiSchema}"/> instance.</returns> public static Dictionary <string, OpenApiSchema> ToOpenApiSchemas(this Type type, NamingStrategy namingStrategy, OpenApiSchemaVisibilityAttribute attribute = null, bool returnSingleSchema = false, int depth = 0) { type.ThrowIfNullOrDefault(); var schema = (OpenApiSchema)null; var schemeName = type.GetOpenApiTypeName(namingStrategy); if (depth == 8) { schema = new OpenApiSchema() { Type = type.ToDataType(), Format = type.ToDataFormat() }; return(new Dictionary <string, OpenApiSchema>() { { schemeName, schema } }); } depth++; if (type.IsJObjectType()) { schema = typeof(object).ToOpenApiSchemas(namingStrategy, null, true, depth).Single().Value; return(new Dictionary <string, OpenApiSchema>() { { schemeName, schema } }); } if (type.IsOpenApiNullable(out var unwrappedValueType)) { schema = unwrappedValueType.ToOpenApiSchemas(namingStrategy, null, true, depth).Single().Value; schema.Nullable = true; return(new Dictionary <string, OpenApiSchema>() { { schemeName, schema } }); } schema = new OpenApiSchema() { Type = type.ToDataType(), Format = type.ToDataFormat() }; if (!attribute.IsNullOrDefault()) { var visibility = new OpenApiString(attribute.Visibility.ToDisplayName()); schema.Extensions.Add("x-ms-visibility", visibility); } if (type.IsUnflaggedEnumType()) { var converterAttribute = type.GetCustomAttribute <JsonConverterAttribute>(); if (!converterAttribute.IsNullOrDefault() && typeof(StringEnumConverter).IsAssignableFrom(converterAttribute.ConverterType)) { var enums = type.ToOpenApiStringCollection(namingStrategy); schema.Type = "string"; schema.Format = null; schema.Enum = enums; schema.Default = enums.First(); } else { var enums = type.ToOpenApiIntegerCollection(); schema.Enum = enums; schema.Default = enums.First(); } } if (type.IsSimpleType()) { return(new Dictionary <string, OpenApiSchema>() { { schemeName, schema } }); } if (type.IsOpenApiDictionary()) { schema.AdditionalProperties = type.GetGenericArguments()[1].ToOpenApiSchemas(namingStrategy, null, true, depth).Single().Value; return(new Dictionary <string, OpenApiSchema>() { { schemeName, schema } }); } if (type.IsOpenApiArray()) { schema.Type = "array"; schema.Items = (type.GetElementType() ?? type.GetGenericArguments()[0]).ToOpenApiSchemas(namingStrategy, null, true, depth).Single().Value; return(new Dictionary <string, OpenApiSchema>() { { schemeName, schema } }); } var allProperties = type.IsInterface ? new[] { type }.Concat(type.GetInterfaces()).SelectMany(i => i.GetProperties()) : type.GetProperties(); var properties = allProperties.Where(p => !p.ExistsCustomAttribute <JsonIgnoreAttribute>()); var retVal = new Dictionary <string, OpenApiSchema>(); foreach (var property in properties) { var visibility = property.GetCustomAttribute <OpenApiSchemaVisibilityAttribute>(inherit: false); var propertyName = property.GetJsonPropertyName(namingStrategy); var ts = property.DeclaringType.GetGenericArguments(); if (!ts.Any()) { if (property.PropertyType.IsUnflaggedEnumType() && !returnSingleSchema) { var recur1 = property.PropertyType.ToOpenApiSchemas(namingStrategy, visibility, false, depth); retVal.AddRange(recur1); var enumReference = new OpenApiReference() { Type = ReferenceType.Schema, Id = property.PropertyType.GetOpenApiReferenceId(false, false) }; var schema1 = new OpenApiSchema() { Reference = enumReference }; schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = schema1; } else if (property.PropertyType.IsSimpleType() || Nullable.GetUnderlyingType(property.PropertyType) != null || returnSingleSchema) { schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = property.PropertyType.ToOpenApiSchemas(namingStrategy, visibility, true, depth).Single().Value; } else if (property.PropertyType.IsOpenApiDictionary()) { var elementType = property.PropertyType.GetGenericArguments()[1]; if (elementType.IsSimpleType() || elementType.IsOpenApiDictionary() || elementType.IsOpenApiArray()) { schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = property.PropertyType.ToOpenApiSchemas(namingStrategy, visibility, true, depth).Single().Value; } else { var recur1 = elementType.ToOpenApiSchemas(namingStrategy, visibility, false, depth); retVal.AddRange(recur1); var elementReference = new OpenApiReference() { Type = ReferenceType.Schema, Id = elementType.GetOpenApiReferenceId(false, false) }; var dictionarySchema = new OpenApiSchema() { Type = "object", AdditionalProperties = new OpenApiSchema() { Reference = elementReference } }; schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = dictionarySchema; } } else if (property.PropertyType.IsOpenApiArray()) { var elementType = property.PropertyType.GetElementType() ?? property.PropertyType.GetGenericArguments()[0]; if (elementType.IsSimpleType() || elementType.IsOpenApiDictionary() || elementType.IsOpenApiArray()) { schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = property.PropertyType.ToOpenApiSchemas(namingStrategy, visibility, true, depth).Single().Value; } else { var elementReference = elementType.ToOpenApiSchemas(namingStrategy, visibility, false, depth); retVal.AddRange(elementReference); var reference1 = new OpenApiReference() { Type = ReferenceType.Schema, Id = elementType.GetOpenApiReferenceId(false, false) }; var arraySchema = new OpenApiSchema() { Type = "array", Items = new OpenApiSchema() { Reference = reference1 } }; schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = arraySchema; } } else { var recur1 = property.PropertyType.ToOpenApiSchemas(namingStrategy, visibility, false, depth); retVal.AddRange(recur1); var reference1 = new OpenApiReference() { Type = ReferenceType.Schema, Id = property.PropertyType.GetOpenApiReferenceId(false, false) }; var schema1 = new OpenApiSchema() { Reference = reference1 }; schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = schema1; } continue; } var reference = new OpenApiReference() { Type = ReferenceType.Schema, Id = property.PropertyType.GetOpenApiRootReferenceId() }; var referenceSchema = new OpenApiSchema() { Reference = reference }; if (!ts.Contains(property.PropertyType)) { if (property.PropertyType.IsOpenApiDictionary()) { reference.Id = property.PropertyType.GetOpenApiReferenceId(true, false); var dictionarySchema = new OpenApiSchema() { Type = "object", AdditionalProperties = referenceSchema }; schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = dictionarySchema; continue; } if (property.PropertyType.IsOpenApiArray()) { reference.Id = property.PropertyType.GetOpenApiReferenceId(false, true); var arraySchema = new OpenApiSchema() { Type = "array", Items = referenceSchema }; schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = arraySchema; continue; } schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = property.PropertyType.ToOpenApiSchemas(namingStrategy, visibility, true, depth).Single().Value; continue; } schema.Properties[namingStrategy.GetPropertyName(propertyName, false)] = referenceSchema; } retVal[schemeName] = schema; return(retVal); }
/// <summary> /// Converts <see cref="Type"/> to <see cref="OpenApiSchema"/>. /// </summary> /// <param name="type"><see cref="Type"/> instance.</param> /// <param name="attribute"><see cref="OpenApiSchemaVisibilityAttribute"/> instance. Default is <c>null</c>.</param> /// <returns><see cref="OpenApiSchema"/> instance.</returns> /// <remarks> /// It runs recursively to build the entire object type. It only takes properties without <see cref="JsonIgnoreAttribute"/>. /// </remarks> public static OpenApiSchema ToOpenApiSchema(this Type type, OpenApiSchemaVisibilityAttribute attribute = null) { type.ThrowIfNullOrDefault(); var schema = (OpenApiSchema)null; if (type == typeof(JObject)) { schema = typeof(object).ToOpenApiSchema(); return(schema); } if (type == typeof(JToken)) { schema = typeof(object).ToOpenApiSchema(); return(schema); } var unwrappedValueType = Nullable.GetUnderlyingType(type); if (!unwrappedValueType.IsNullOrDefault()) { schema = unwrappedValueType.ToOpenApiSchema(); schema.Nullable = true; return(schema); } schema = new OpenApiSchema() { Type = type.ToDataType(), Format = type.ToDataFormat() }; if (!attribute.IsNullOrDefault()) { var visibility = new OpenApiString(attribute.Visibility.ToDisplayName()); schema.Extensions.Add("x-ms-visibility", visibility); } if (type.IsSimpleType()) { return(schema); } if (typeof(IDictionary).IsAssignableFrom(type)) { schema.AdditionalProperties = type.GetGenericArguments()[1].ToOpenApiSchema(); return(schema); } if (type.IsOpenApiArray()) { schema.Type = "array"; schema.Items = (type.GetElementType() ?? type.GetGenericArguments()[0]).ToOpenApiSchema(); return(schema); } var properties = type.GetProperties() .Where(p => !p.ExistsCustomAttribute <JsonIgnoreAttribute>()); foreach (var property in properties) { var visiblity = property.GetCustomAttribute <OpenApiSchemaVisibilityAttribute>(inherit: false); var propertyName = property.GetJsonPropertyName(); schema.Properties[propertyName] = property.PropertyType.ToOpenApiSchema(visiblity); } return(schema); }