Generate yaml swagger using Swashbuckle
Asked Answered
F

4

14

I have had no problem getting a json file in my Web API project using Microsoft's tutorial.

Due to some requirement I would like to be able to retrieve a yaml file. But the problem is there is no hook I could find to make this possible.

Does anyone know any workaround for this problem?

Francophobe answered 14/7, 2017 at 10:39 Comment(0)
T
19

V 5.6 supports producing YAML files. How to use it:

app.UseSwaggerUI(x => { x.SwaggerEndpoint("/swagger/v1/swagger.yaml", "Zeipt Dashboard API"); });
Typecase answered 16/9, 2020 at 15:1 Comment(1)
It works, but I have to remove /swagger/: app.UseSwaggerUI(x => { x.SwaggerEndpoint("v1/swagger.yaml", "Zeipt Dashboard API"); });Uvea
C
7

An option will be to add an IDocumentFilter to your project, here are a couple of samples:

    private class YamlDocumentFilter : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            string file = AppDomain.CurrentDomain.BaseDirectory + "swagger_yaml.txt";
            if (!File.Exists(file))
            {
                var serializer = new YamlSerializer();
                serializer.SerializeToFile(file, swaggerDoc);
            }
        }
    }

...

    private class YamlDocumentFilter : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            string file = AppDomain.CurrentDomain.BaseDirectory + "swagger.yaml";
            if (!File.Exists(file))
            {
                var serializer = new YamlDotNet.Serialization.Serializer();
                using (var writer = new StringWriter())
                {
                    serializer.Serialize(writer, swaggerDoc);
                    var stream = new StreamWriter(file);
                    stream.WriteLine(writer.ToString());
                }
            }
        }
    }

but that depends on your project if adding an additional reference to YamlSerializer or YamlDotNet is acceptable.

Cassowary answered 17/7, 2017 at 19:23 Comment(5)
This seems to be the right way to go, I have not been able to verify it. But it might be because I am deploying to a service fabric.Francophobe
arghhh! the devil in the details (service fabric) yes you probably need to modify that example or try with a different dependency...Cassowary
I added a sample using YamlSerializer that code looks a lot simpler and I verified it that it works on Azure: swashbuckletest.azurewebsites.net/swagger_yaml.txtCassowary
@HelderSepu can you provide a more complete example, e.g. libraries, namespaces, usage etc.Missend
@PawełG. Take a look here: github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/…Cassowary
M
2

Based on idea given by @HelderSepu I managed to get Swashbuckle.AspNetCore together with YamlDotNet generate the following YAML passing validation on https://bigstickcarpet.com/swagger-parser/www/index.html.

I know this solution is not ideal, but might be some starting point in case someone has the same problem:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.TypeInspectors;

namespace SwaggerPhun
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info
                {
                    Version = "v1",
                    Title = "File Comment API",
                    Description = "A simple example ASP.NET Core Web API",
                    //TermsOfService = "None",
                    Contact = new Contact
                    {
                        Name = "Pawel",
                        Email = "[email protected]",
                    },
                    License = new License
                    {
                        Name = "Use under LICX",
                        Url = "https://example.com/license"
                    },
                });
                c.DocumentFilter<YamlDocumentFilter>();

                // Set the comments path for the Swagger JSON and UI.
                var xmlFile = $"{Assembly.GetEntryAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();

            // Enable middleware to serve generated Swagger as a JSON endpoint.
            app.UseSwagger();

            // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            });
        }

        private class YamlDocumentFilter : IDocumentFilter
        {
            public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
            {
                var builder = new SerializerBuilder();
                builder.WithNamingConvention(new HyphenatedNamingConvention());
                builder.WithTypeInspector(innerInspector => new PropertiesIgnoreTypeInspector(innerInspector));

                var serializer = builder.Build();

                using (var writer = new StringWriter())
                {
                    serializer.Serialize(writer, swaggerDoc);

                    var file = AppDomain.CurrentDomain.BaseDirectory + "swagger_yaml.txt";
                    using (var stream = new StreamWriter(file))
                    {
                        var result = writer.ToString();
                        stream.WriteLine(result.Replace("2.0", "\"2.0\"").Replace("ref:", "$ref:"));
                    }
                }
            }
        }

        private class PropertiesIgnoreTypeInspector : TypeInspectorSkeleton
        {
            private readonly ITypeInspector _typeInspector;

            public PropertiesIgnoreTypeInspector(ITypeInspector typeInspector)
            {
                this._typeInspector = typeInspector;
            }

            public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
            {
                return _typeInspector.GetProperties(type, container).Where(p => p.Name != "extensions" && p.Name != "operation-id");
            }

        }
    }
}
Missend answered 6/4, 2018 at 14:57 Comment(2)
Since I had a bit of time, I took the code and crafted a library stub that mimics the original Swashbuckle but adds a yaml endpoint - the source can be found in: github.com/pablonautic/Swashbuckle.AspNetCore.YamlMissend
Can we save the swagger.json file to local by this method?Sparkle
L
0

The UseSwagger() function automatically supports json and yaml together (see swashbuckle sources middleware class), just navigate to the json url and change .json to .yaml manually.

If that is not the case then you probably have overwritten SwaggerOption.RouteTemplate. In that case just make sure that whatever you have overwritten it with ends with .{json|yaml} instead of .json.

Libyan answered 15/8 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.