Pārlūkot izejas kodu

Merge pull request #2925 from crobibero/redoc

Enhance Swagger Generation
Bond-009 5 gadi atpakaļ
vecāks
revīzija
f2bace2a07

+ 3 - 1
Emby.Server.Implementations/Browser/BrowserLauncher.cs

@@ -1,5 +1,7 @@
 using System;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
+using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 
 namespace Emby.Server.Implementations.Browser
@@ -24,7 +26,7 @@ namespace Emby.Server.Implementations.Browser
         /// <param name="appHost">The app host.</param>
         public static void OpenSwaggerPage(IServerApplicationHost appHost)
         {
-            TryOpenUrl(appHost, "/swagger/index.html");
+            TryOpenUrl(appHost, "/api-docs/swagger");
         }
 
         /// <summary>

+ 2 - 1
Jellyfin.Api/Jellyfin.Api.csproj

@@ -10,7 +10,8 @@
     <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.3" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
-    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.3.3" />
+    <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.3.3" />
   </ItemGroup>
 
   <ItemGroup>

+ 29 - 7
Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs

@@ -1,4 +1,4 @@
-using Jellyfin.Server.Middleware;
+using MediaBrowser.Controller.Configuration;
 using Microsoft.AspNetCore.Builder;
 
 namespace Jellyfin.Server.Extensions
@@ -12,17 +12,39 @@ namespace Jellyfin.Server.Extensions
         /// Adds swagger and swagger UI to the application pipeline.
         /// </summary>
         /// <param name="applicationBuilder">The application builder.</param>
+        /// <param name="serverConfigurationManager">The server configuration.</param>
         /// <returns>The updated application builder.</returns>
-        public static IApplicationBuilder UseJellyfinApiSwagger(this IApplicationBuilder applicationBuilder)
+        public static IApplicationBuilder UseJellyfinApiSwagger(
+            this IApplicationBuilder applicationBuilder,
+            IServerConfigurationManager serverConfigurationManager)
         {
-            applicationBuilder.UseSwagger();
-
             // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
             // specifying the Swagger JSON endpoint.
-            return applicationBuilder.UseSwaggerUI(c =>
+
+            var baseUrl = serverConfigurationManager.Configuration.BaseUrl.Trim('/');
+            if (!string.IsNullOrEmpty(baseUrl))
             {
-                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jellyfin API V1");
-            });
+                baseUrl += '/';
+            }
+
+            return applicationBuilder
+                .UseSwagger(c =>
+                {
+                    // Custom path requires {documentName}, SwaggerDoc documentName is 'api-docs'
+                    c.RouteTemplate = $"/{baseUrl}{{documentName}}/openapi.json";
+                })
+                .UseSwaggerUI(c =>
+                {
+                    c.DocumentTitle = "Jellyfin API";
+                    c.SwaggerEndpoint($"/{baseUrl}api-docs/openapi.json", "Jellyfin API");
+                    c.RoutePrefix = $"{baseUrl}api-docs/swagger";
+                })
+                .UseReDoc(c =>
+                {
+                    c.DocumentTitle = "Jellyfin API";
+                    c.SpecUrl($"/{baseUrl}api-docs/openapi.json");
+                    c.RoutePrefix = $"{baseUrl}api-docs/redoc";
+                });
         }
     }
 }

+ 21 - 1
Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs

@@ -1,3 +1,8 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json.Serialization;
 using Jellyfin.Api;
 using Jellyfin.Api.Auth;
 using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy;
@@ -91,7 +96,22 @@ namespace Jellyfin.Server.Extensions
         {
             return serviceCollection.AddSwaggerGen(c =>
             {
-                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Jellyfin API", Version = "v1" });
+                c.SwaggerDoc("api-docs", new OpenApiInfo { Title = "Jellyfin API" });
+
+                // Add all xml doc files to swagger generator.
+                var xmlFiles = Directory.GetFiles(
+                    AppContext.BaseDirectory,
+                    "*.xml",
+                    SearchOption.TopDirectoryOnly);
+
+                foreach (var xmlFile in xmlFiles)
+                {
+                    c.IncludeXmlComments(xmlFile);
+                }
+
+                // Order actions by route path, then by http method.
+                c.OrderActionsBy(description =>
+                    $"{description.ActionDescriptor.RouteValues["controller"]}_{description.HttpMethod}");
             });
         }
     }

+ 1 - 1
Jellyfin.Server/Program.cs

@@ -529,7 +529,7 @@ namespace Jellyfin.Server
             var inMemoryDefaultConfig = ConfigurationOptions.DefaultConfiguration;
             if (startupConfig != null && !startupConfig.HostWebClient())
             {
-                inMemoryDefaultConfig[HttpListenerHost.DefaultRedirectKey] = "swagger/index.html";
+                inMemoryDefaultConfig[HttpListenerHost.DefaultRedirectKey] = "api-docs/swagger";
             }
 
             return config

+ 1 - 1
Jellyfin.Server/Startup.cs

@@ -69,7 +69,7 @@ namespace Jellyfin.Server
             app.Use(serverApplicationHost.ExecuteWebsocketHandlerAsync);
 
             // TODO use when old API is removed: app.UseAuthentication();
-            app.UseJellyfinApiSwagger();
+            app.UseJellyfinApiSwagger(_serverConfigurationManager);
             app.UseRouting();
             app.UseAuthorization();
             app.UseEndpoints(endpoints =>