Vogen icon indicating copy to clipboard operation
Vogen copied to clipboard

OpenAPI Support Extension

Open Aragas opened this issue 1 year ago • 4 comments

Describe the feature

Add support for OpenAPI/Swagger schema generation

public class VogenSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.GetCustomAttribute<ValueObjectAttribute>() is not { } attribute)
            return;

        // Since we don't hold the actual type, we ca only use the generic attribute
        var type = attribute.GetType();
        if (!type.IsGenericType || type.GenericTypeArguments.Length != 1)
            return;
        var schemaValueObject = context.SchemaGenerator.GenerateSchema(type.GenericTypeArguments[0], context.SchemaRepository, context.MemberInfo, context.ParameterInfo);
        CopyPublicProperties(schemaValueObject, schema);

        
        // By adding `public Type UnderlyingType { get; }` to `ValueObjectAttribute` this can be simplified
        var schemaValueObject = context.SchemaGenerator.GenerateSchema(attribute.UnderlyingType, context.SchemaRepository, context.MemberInfo, context.ParameterInfo);
        CopyPublicProperties(schemaValueObject, schema);
    }

    private static void CopyPublicProperties<T>(T oldObject, T newObject) where T : class
    {
        const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

        if (ReferenceEquals(oldObject, newObject)) return;

        var type = typeof(T);
        var propertyList = type.GetProperties(flags);
        if (propertyList.Length <= 0) return;

        foreach (var newObjProp in propertyList)
        {
            var oldProp = type.GetProperty(newObjProp.Name, flags)!;
            if (!oldProp.CanRead || !newObjProp.CanWrite) continue;

            var value = oldProp.GetValue(oldObject);
            newObjProp.SetValue(newObject, value);
        }
    }
}

Usage:

services.AddSwaggerGen(opt =>
{
    opt.SchemaFilter<VogenSchemaFilter>();
}

Aragas avatar Oct 28 '23 12:10 Aragas

Thanks for another great suggestion. I think for this one too, we'll need a new NuGet package as wouldn't want the default package to take on extra dependencies (assuming aspnet core and Microsoft.OpenApi?)

SteveDunn avatar Oct 30 '23 22:10 SteveDunn

+1

JoshuaNitschke avatar Nov 28 '23 20:11 JoshuaNitschke

Hi @Aragas - looking at this one, are you saying that you want Vogen to generate the implementation above (the class that you provided), or are you suggesting that it generates an implementation of ISchemaFilter for every value object that it generates?

SteveDunn avatar May 01 '24 06:05 SteveDunn

Hi @Aragas - looking at this one, are you saying that you want Vogen to generate the implementation above (the class that you provided), or are you suggesting that it generates an implementation of ISchemaFilter for every value object that it generates?

Yea, it's a global extension. We don't need a per-object implementation here

Aragas avatar May 05 '24 08:05 Aragas

Implemented in 4.0.5

SteveDunn avatar May 26 '24 09:05 SteveDunn