Vogen icon indicating copy to clipboard operation
Vogen copied to clipboard

AspNetCore.OpenApi support

Open CheloXL opened this issue 1 year ago • 14 comments

Describe the feature

Now that .net 9 is out and Swashbuckle was removed, it would be nice to have support for the new AspNetCore.OpenApi.

CheloXL avatar Nov 15 '24 14:11 CheloXL

Hi @CheloXL - this should already be supported https://stevedunn.github.io/Vogen/use-in-swagger.html

Please let me know if there's anything missing

SteveDunn avatar Nov 16 '24 21:11 SteveDunn

Yes, but no, but yes, but no. SwaggerOptions is swagger specific. In .net 9, swagger doesn't exist anymore (of course you can still use it, but I would prefer to migrate to the native support). So, this feature request is to use .net 9 specific open api support.

CheloXL avatar Nov 17 '24 18:11 CheloXL

I see, good point! Thanks for the feedback.

SteveDunn avatar Nov 19 '24 05:11 SteveDunn

Quick and dirty schema transformer that seems to do the trick

public sealed class VogenSchemaTransformer : IOpenApiSchemaTransformer
{
    /// <inheritdoc />
    public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken)
    {
        if (context.JsonTypeInfo.Type.GetCustomAttribute(typeof(ValueObjectAttribute<>)) is not { } attribute)
        {
            return Task.CompletedTask;
        }
        var primitiveType = attribute.GetType();
        var primitiveTypeSchema = primitiveType.GenericTypeArguments[0].MapTypeToOpenApiPrimitiveType();
        if (primitiveTypeSchema == null)
        {
            return Task.CompletedTask;
        }

        schema.Type = primitiveTypeSchema.Type;
        schema.Format = primitiveTypeSchema.Format;
        schema.Nullable = primitiveTypeSchema.Nullable;
        return Task.CompletedTask;
    }
}

mvn-dips avatar Mar 14 '25 12:03 mvn-dips

is there any news? i think Microsoft.OpenApi is so important than Swashbuckle

mo3in avatar Apr 15 '25 22:04 mo3in

Apologies, I haven't had a chance to look at this one. It should be quite similar to the Swashbuckle implementation, so I'm hoping someone can pick this up and use that as a guide

SteveDunn avatar Jun 05 '25 05:06 SteveDunn

@SteveDunn I see the related PR has been merged, any chance for a release soon? 🫶

rigtigeEmil avatar Jun 25 '25 18:06 rigtigeEmil

It's in the latest beta. Would be grateful if you could give it a try and then I'll do a release

SteveDunn avatar Jun 25 '25 19:06 SteveDunn

Doesn't work for me, I'm unsure if I'm doing something wrong. I'm using string-backed id's. Example:

[ValueObject<string>]
public readonly partial struct CustomerId
{
    private static string Prefix => IdHelpers.CUSTOMER_ID_PREFIX;

    public static CustomerId New() => From(IdHelpers.New(Prefix));

    private static Validation Validate(string input) =>
        input.StartsWith(Prefix)
            ? Validation.Ok
            : Validation.Invalid($"Invalid ID format. It should start with {Prefix}.");
}

I've added this in my Program.cs:

[assembly: VogenDefaults(
    underlyingType: typeof(string),
    openApiSchemaCustomizations: OpenApiSchemaCustomizations.GenerateOpenApiMappingExtensionMethod
)]

(..)

services.AddOpenApi(x => x.MapVogenTypesInGilbert_API_BFF());

The generated extension method also does not look that useful 🥲

public static class VogenOpenApiExtensions
{
	public static global::Microsoft.AspNetCore.OpenApi.OpenApiOptions MapVogenTypesInGilbert_API_BFF(this global::Microsoft.AspNetCore.OpenApi.OpenApiOptions options)
	{
		options.AddSchemaTransformer((schema, context, cancellationToken) =>
		{
			return global::System.Threading.Tasks.Task.CompletedTask;
		});

		return options;
	}
}

rigtigeEmil avatar Jun 25 '25 19:06 rigtigeEmil

@amyboose @SteveDunn do either of you know what I'm doing wrong?

rigtigeEmil avatar Jun 26 '25 20:06 rigtigeEmil

Thanks for the feedback @rigtigeEmil - I'll take a look shortly.

SteveDunn avatar Jun 30 '25 10:06 SteveDunn

Now that this is merged, can I propose some scope creep? :) In #53 it was proposed to support validation using System.ComponentModel.DataAnnotations. Of course we already have validation in vogen, but what we do not have is setting properties such as the range of values allowed in the openapi spec. In our codebase we make use of these attributes to set the fields in the generated openapi spec via various methods such as https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle#data-annotations and FluentValidation integration. To fully migrate to using vogen types in the api we somehow need to replicate this behavior. Seeing as there is now a custom AddSchemaTransformer we could further enhance this to also look at these attributes. One way to do that is to add these attributes to a dummy field/property on the type and generate code to set the ExclusiveMinimum and ExclusiveMaximum fields on the OpenApiSchema whenever a RangeAttribute is added.

Is it ok I give this a try and make another PR for this @SteveDunn ?

ajeckmans avatar Jul 08 '25 21:07 ajeckmans

@SteveDunn @amyboose any chance either of you know what's wrong with it?

rigtigeEmil avatar Jul 20 '25 11:07 rigtigeEmil

@rigtigeEmil - apologies for the very long delay - I missed this message originally and have only just spotted it as I prune some old issues.

Some work was recently don't for v2.0 of the open api spec. Could you give it another try, and if it doesn't work, could you provide a minimal reproduction project and I'd be happy to fix it.

Many thanks.

SteveDunn avatar Nov 25 '25 07:11 SteveDunn