RicoSuter / NSwag

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

Generate swagger specification for given action type #1060

Open codestellar opened 6 years ago

codestellar commented 6 years ago

Currently, there is an option to generate swagger specification for given controller type. I am looking for generating swagger specification for given action type. This is the thought:

  1. Create IOperationFilter or OperationProcessor to add extension for code sample.

  2. Generate swagger spec for each operation and inject in the x-code-sample property.

  3. Implement javascript in swagger UI to get that values from swagger specs. I can inject custom javascript if I use Swashbuckle but could not inject custom javascript using NSwag.

codestellar commented 6 years ago

@rsuter will there be any support provided

RicoSuter commented 6 years ago

Sorry, I don't understand your issue?

codestellar commented 6 years ago

@RSuter Here is the operation filter code:

` public class AddCodeSamplesOperationFilter : IOperationFilter {

    private readonly string _language;
    private readonly string _source;
    private const string ExtensionKey = "x-code-samples";

    public void Apply(Operation operation, OperationFilterContext context)
    {

        // Get Controller and action for which Swagger Spec is required
        var appAssembly = (context.ApiDescription.ActionDescriptor as ControllerActionDescriptor).ControllerTypeInfo.Assembly;
        var controllerName = (context.ApiDescription.ActionDescriptor as ControllerActionDescriptor).ControllerTypeInfo.FullName;

        var controllersList = appAssembly.GetTypes().Where(type => typeof(Microsoft.AspNetCore.Mvc.Controller)
                                .IsAssignableFrom(type) && type.FullName.Equals(controllerName));

        var actionName = (context.ApiDescription.ActionDescriptor as ControllerActionDescriptor).ActionName;

        // Generate Swagger Specification
        var swaggerGeneratorSettings = new WebApiToSwaggerGeneratorSettings
        {
            DefaultUrlTemplate = "api/{controller}/{action}/{id}"                
        };
        var swaggerGenerator = new WebApiToSwaggerGenerator(swaggerGeneratorSettings);
        var swaggerSpec = swaggerGenerator.GenerateForControllersAsync(controllersList).GetAwaiter().GetResult();              

        // Remove unnecessary paths from swagger spec
        var pathsToRemove = swaggerSpec.Paths.Keys.Where(path => !path.Equals($"/{context.ApiDescription.RelativePath}")).ToList();
        foreach (var path in pathsToRemove)
        {
            swaggerSpec.Paths.Remove(path);
        }

        // Generate Client Code 
        var csharpClientSettings = new SwaggerToCSharpClientGeneratorSettings
        {
            ClassName = "{controller}Client",
            GenerateDtoTypes = false,
            GenerateExceptionClasses = false,
            GenerateResponseClasses = false,
            DisposeHttpClient = false,
            CSharpGeneratorSettings = {
                Namespace = "Ciam.Client"
            },
            InjectHttpClient = true
        };

        var csharpClientGenerator = new SwaggerToCSharpClientGenerator(swaggerSpec, csharpClientSettings);
        var csharpCode = csharpClientGenerator.GenerateFile();

        // Inject Generated Swagger Code in Swashbuckle Swagger Spec
        var codeSamples = new List<CodeSample>();
        codeSamples.Add(new CodeSample
        {
            Language = "csharp",
            Source = string.Format("C# Code for {0}", csharpCode)
        });
        codeSamples.Add(new CodeSample
        {
            Language = "angular",
            Source = string.Format("Angular Code for {0}", operation.OperationId)
        });
        operation.Extensions.Add(ExtensionKey, codeSamples);
    }

}

internal class CodeSample
{
    [JsonProperty("lang")]
    public string Language { get; set; }

    [JsonProperty("source")]
    public string Source { get; set; }
}`

I am using Swashbuckle and writing this operationfilter. So I want to generate Swagger Spec only for particular endpoint/action at one time. Currently, I am removing other operations each time. :(

I could not find a way to inject custom javascript when using NSwag. So, I am using swashbuckle and have modified Swagger UI as shown in the figure below. Next I am writing javascript to read x-code-samples and will fit the code accordingly.

image

codestellar commented 6 years ago

@RSuter

RicoSuter commented 6 years ago

Injecting custom javascript into Swagger UI should be simple to add... How is this solved/configured in Swashbuckle?

codestellar commented 6 years ago

@Rsuter Swashbuckle gives the option to inject custom javascript in options like this:

image The only thing is whether I user operation filter or document filter generating client code per action wise would be a great optimization for me.

Currently it is: swaggerGenerator.GenerateForControllersAsync(controllersList).GetAwaiter().GetResult(); If we can have something like : swaggerGenerator.GenerateForActionAsync(actionName).GetAwaiter().GetResult(); where action name is string, should generate client side method only.

RicoSuter commented 6 years ago

I think you can easily implement this method yourself, with a custom operation processor... Adding the javascript injection settings should be simple. How are these injection js configured in Swagger UI?

codestellar commented 6 years ago

I ended up creating this npm package for my requirement https://www.npmjs.com/package/swaggerui-snippets