RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.77k stars 1.29k forks source link

ApiConventionMethod support. #2542

Open 0xorial opened 4 years ago

0xorial commented 4 years ago

Is it supposed to be working? As soon as I extract response types into a convention class it stops working as if NSwag ignores it completely...

RicoSuter commented 4 years ago

It should work because we use ASP.NET Core API explorer internally which should then reflect these conventions.

/cc @dougbu is this assumption correct?

sandord commented 4 years ago

I'm having trouble getting this to work as well. I don't see any effect of the attributes in my convention class on the NSwag output.

I've applied the convention to the assembly, controller and actions but none of those work.

UPDATE

Apparently, the API Conventions are honored when generating clients using NSwag.MSBuild but not when generating clients using a code based client generator. In that case, the OpenApiDocument that is a result of the WebApiOpenApiDocumentGenerator.GenerateForControllersAsync call simply doesn't contain any effects of the convention.

sandord commented 4 years ago

I wrote a test to verify whether the convention is taken into account and it fails.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using NSwag.Generation.WebApi;
using Xunit;

namespace NSwag.CodeGeneration.CSharp.Tests
{
    public class WebApiConventionsTests
    {
        public static class CustomApiConventions
        {
            [ProducesResponseType(StatusCodes.Status409Conflict)]
            [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Exact)]
            public static void Foo() { }
        }

        public class TestController : Controller
        {
            [Route("Foo")]
            [ApiConventionMethod(typeof(CustomApiConventions), nameof(CustomApiConventions.Foo))]
            public string Foo()
            {
                throw new NotImplementedException();
            }
        }

        [Fact]
        public async Task When_WebApiConvention_is_applied_then_the_implied_response_type_is_handled()
        {
            //// Arrange
            var swaggerGen = new WebApiOpenApiDocumentGenerator(new WebApiOpenApiDocumentGeneratorSettings());
            var document = await swaggerGen.GenerateForControllerAsync<TestController>();

            //// Act
            var codeGen = new CSharpClientGenerator(document, new CSharpClientGeneratorSettings());
            var code = codeGen.GenerateFile();

            //// Assert
            Assert.Contains("\"409\"", code);
        }
    }
}
RicoSuter commented 4 years ago

Of course it can only work with the AspNetCore generator (WebApis is deprecated for core and should only be used for aspnet mvc)

sandord commented 4 years ago

Ah, I see. The Controller base class should have given that away since it of course is ControllerBase for AspNetCore.

sandord commented 4 years ago

Ah, so I didn't realize there was a AspNetCoreOpenApiDocumentGenerator as opposed to the WebApiOpenApiDocumentGenerator I was using. This solves it for me.

RicoSuter commented 4 years ago

Good, you could still create a pr with your test so that this is covered