From 9d688386eddd5c64e7f978fd769c05e39b4e19bc Mon Sep 17 00:00:00 2001 From: Pavel Zhur Date: Thu, 18 Jul 2024 15:07:04 +0300 Subject: [PATCH] https://github.com/vitalybibikov/AzureExtensions.Swashbuckle?tab=readme-ov-file --- .../Functions/VExternal1/TonalitiesLoops.cs | 4 +- .../HarmonyDB.Index.Api.csproj | 1 + .../HarmonyDB.Index.Api/Program.cs | 71 ++++++++++++++++++- .../HarmonyDB.Index.Api/SwaggerController.cs | 57 +++++++++++++++ 4 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 HarmonyDB.Index/HarmonyDB.Index.Api/SwaggerController.cs diff --git a/HarmonyDB.Index/HarmonyDB.Index.Api/Functions/VExternal1/TonalitiesLoops.cs b/HarmonyDB.Index/HarmonyDB.Index.Api/Functions/VExternal1/TonalitiesLoops.cs index 6d3db14b..2e81aafa 100644 --- a/HarmonyDB.Index/HarmonyDB.Index.Api/Functions/VExternal1/TonalitiesLoops.cs +++ b/HarmonyDB.Index/HarmonyDB.Index.Api/Functions/VExternal1/TonalitiesLoops.cs @@ -1,4 +1,5 @@ -using HarmonyDB.Index.Analysis.Em.Models; +using System.Net; +using HarmonyDB.Index.Analysis.Em.Models; using HarmonyDB.Index.Analysis.Em.Services; using HarmonyDB.Index.Analysis.Tools; using HarmonyDB.Index.Api.Client; @@ -35,6 +36,7 @@ public TonalitiesLoops(ILoggerFactory loggerFactory, SecurityContext securityCon _options = options.Value; } + [ProducesResponseType(200)] [Function(IndexApiUrls.VExternal1TonalitiesLoops)] public Task Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req, [FromBody] LoopsRequest request) => RunHandler(request); diff --git a/HarmonyDB.Index/HarmonyDB.Index.Api/HarmonyDB.Index.Api.csproj b/HarmonyDB.Index/HarmonyDB.Index.Api/HarmonyDB.Index.Api.csproj index 5adc23f1..3457c405 100644 --- a/HarmonyDB.Index/HarmonyDB.Index.Api/HarmonyDB.Index.Api.csproj +++ b/HarmonyDB.Index/HarmonyDB.Index.Api/HarmonyDB.Index.Api.csproj @@ -9,6 +9,7 @@ + diff --git a/HarmonyDB.Index/HarmonyDB.Index.Api/Program.cs b/HarmonyDB.Index/HarmonyDB.Index.Api/Program.cs index 52e3d09e..501d125b 100644 --- a/HarmonyDB.Index/HarmonyDB.Index.Api/Program.cs +++ b/HarmonyDB.Index/HarmonyDB.Index.Api/Program.cs @@ -1,3 +1,6 @@ +using System.Reflection; +using AzureFunctions.Extensions.Swashbuckle; +using AzureFunctions.Extensions.Swashbuckle.Settings; using HarmonyDB.Index.Api.Client; using HarmonyDB.Index.Api.Models; using HarmonyDB.Index.Api.Services; @@ -8,11 +11,14 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi; +using Microsoft.OpenApi.Models; using Nito.AsyncEx; using OneShelf.Authorization.Api.Client; using OneShelf.Collectives.Api.Client; using OneShelf.Common.Api; using OneShelf.Common.Api.WithAuthorization; +using Swashbuckle.AspNetCore.SwaggerGen; var host = new HostBuilder() .ConfigureApi() @@ -31,7 +37,70 @@ .AddIndexBusinessLogic(context.Configuration) .AddSecurityContext() .Configure(o => context.Configuration.GetSection(nameof(IndexApiOptions)).Bind(o)); + + services.AddSwashBuckle(opts => + { + // If you want to add Newtonsoft support insert next line + // opts.AddNewtonsoftSupport = true; + opts.RoutePrefix = "api"; + opts.SpecVersion = OpenApiSpecVersion.OpenApi3_0; + opts.AddCodeParameter = true; + opts.PrependOperationWithRoutePrefix = true; + opts.XmlPath = "TestFunction.xml"; + opts.Documents = new[] + { + new SwaggerDocument + { + Name = "v1", + Title = "Swagger document", + Description = "Swagger test document", + Version = "v2" + }, + new SwaggerDocument + { + Name = "v2", + Title = "Swagger document 2", + Description = "Swagger test document 2", + Version = "v2" + } + }; + opts.Title = "Swagger Test"; + //opts.OverridenPathToSwaggerJson = new Uri("http://localhost:7071/api/Swagger/json"); + opts.ConfigureSwaggerGen = x => + { + //custom operation example + x.CustomOperationIds(apiDesc => apiDesc.TryGetMethodInfo(out MethodInfo methodInfo) + ? methodInfo.Name + : new Guid().ToString()); + + //custom filter example + //x.DocumentFilter(); + + //oauth2 + x.AddSecurityDefinition("oauth2", + new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows + { + Implicit = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("https://your.idserver.net/connect/authorize"), + Scopes = new Dictionary + { + { "api.read", "Access read operations" }, + { "api.write", "Access write operations" } + } + } + } + }); + }; + + // set up your client ID if your API is protected + opts.ClientId = "your.client.id"; + opts.OAuth2RedirectPath = "http://localhost:7071/api/swagger/oauth2-redirect"; + }); }) .Build(); -host.Run(); +host.Run(); \ No newline at end of file diff --git a/HarmonyDB.Index/HarmonyDB.Index.Api/SwaggerController.cs b/HarmonyDB.Index/HarmonyDB.Index.Api/SwaggerController.cs new file mode 100644 index 00000000..a904f6ad --- /dev/null +++ b/HarmonyDB.Index/HarmonyDB.Index.Api/SwaggerController.cs @@ -0,0 +1,57 @@ +using AzureFunctions.Extensions.Swashbuckle; +using Microsoft.Azure.Functions.Worker; +using Swashbuckle.AspNetCore.Annotations; + +public class SwaggerController +{ + private readonly ISwashBuckleClient swashBuckleClient; + + public SwaggerController(ISwashBuckleClient swashBuckleClient) + { + this.swashBuckleClient = swashBuckleClient; + } + + [SwaggerIgnore] + [Function("SwaggerJson")] + public async Task SwaggerJson( + [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Swagger/json")] + HttpRequestData req) + { + return await this.swashBuckleClient.CreateSwaggerJsonDocumentResponse(req); + } + + [SwaggerIgnore] + [Function("SwaggerYaml")] + public async Task SwaggerYaml( + [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Swagger/yaml")] + HttpRequestData req) + { + return await this.swashBuckleClient.CreateSwaggerYamlDocumentResponse(req); + } + + [SwaggerIgnore] + [Function("SwaggerUi")] + public async Task SwaggerUi( + [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Swagger/ui")] + HttpRequestData req) + { + return await this.swashBuckleClient.CreateSwaggerUIResponse(req, "swagger/json"); + } + + /// + /// This is only needed for OAuth2 client. This redirecting document is normally served + /// as a static content. Functions don't provide this out of the box, so we serve it here. + /// Don't forget to set OAuth2RedirectPath configuration option to reflect this route. + /// + /// + /// + /// + [SwaggerIgnore] + [Function("SwaggerOAuth2Redirect")] + public async Task SwaggerOAuth2Redirect( + [HttpTrigger(AuthorizationLevel.Function, "get", Route = "swagger/oauth2-redirect")] + HttpRequestData req) + { + return await this.swashBuckleClient.CreateSwaggerOAuth2RedirectResponse(req); + } +} \ No newline at end of file