Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public class ApiSchemaOptions
{
public bool NameAndOrderRequestBody { get; set; }

public OpenApiSpecificationVersion OpenApiSpecificationVersion { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public enum ApiSchemaVersion
{
V1,
V2
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public class NameAndOrderRequestBodyFilter: IRequestBodyFilter
{
private readonly SwaggerOptions _swaggerOptions;

public NameAndOrderRequestBodyFilter(IOptions<SwaggerOptions> swaggerOptions)
{
_swaggerOptions = swaggerOptions.Value;
}

public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context)
{
// Even if it's v2 or request body shouldn't be named
// we want name it because of bugs and different approaches in generation tools
var bodyName = _swaggerOptions.Schema.NameAndOrderRequestBody
? context.BodyParameterDescription.Name
: "body";
requestBody.Extensions.Add("x-name", new OpenApiString(bodyName));
requestBody.Extensions.Add("x-codegen-request-body-name", new OpenApiString(bodyName));
requestBody.Extensions.Add("x-ms-requestBody-name", new OpenApiString(bodyName));

if (_swaggerOptions.Schema.NameAndOrderRequestBody)
{
var bodyPosition = context.BodyParameterDescription.ParameterInfo().Position;
requestBody.Extensions.Add("x-position", new OpenApiInteger(bodyPosition));
requestBody.Extensions.Add("x-ms-requestBody-index", new OpenApiInteger(bodyPosition));
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public enum OpenApiSpecificationVersion
{
V2,
V3
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public class ParameterOrderFilter: IParameterFilter
{
private readonly SwaggerOptions _swaggerOptions;

public ParameterOrderFilter(IOptions<SwaggerOptions> swaggerOptions)
{
_swaggerOptions = swaggerOptions.Value;
}

public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
{
if (_swaggerOptions.Schema.NameAndOrderRequestBody)
{
// Explicitly specify parameters position
// Position for store and language is unknown and they should be last, so use int.MaxValue relative values
if (context.ParameterInfo != null)
{
parameter.Extensions.Add("x-position", new OpenApiInteger(context.ParameterInfo.Position));
}
else
{
switch (parameter.Name)
{
case "store":
parameter.Extensions.Add("x-position", new OpenApiInteger(int.MaxValue - 1));
break;
case "language":
parameter.Extensions.Add("x-position", new OpenApiInteger(int.MaxValue));
break;
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public class RequireRequestBodyFilter: IRequestBodyFilter
{
public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context)
{
requestBody.Required = true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace VirtoCommerce.Storefront.Infrastructure.Swagger
{
public class SwaggerOptions
{
public ApiSchemaOptions Schema { get; set; }
}
}
18 changes: 14 additions & 4 deletions VirtoCommerce.Storefront/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,28 +346,33 @@ public void ConfigureServices(IServiceCollection services)
options.MaxAge = TimeSpan.FromDays(30);
});

services.Configure<SwaggerOptions>(Configuration.GetSection("Swagger").Bind);

// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Storefront REST API documentation", Version = "v1" });
c.IgnoreObsoleteProperties();
c.IgnoreObsoleteActions();
c.ParameterFilter<ParameterOrderFilter>();
c.RequestBodyFilter<NameAndOrderRequestBodyFilter>();
c.RequestBodyFilter<RequireRequestBodyFilter>();
// To include 401 response type to actions that requires Authorization
c.OperationFilter<AuthResponsesOperationFilter>();
c.OperationFilter<ConsumeFromBodyFilter>();
c.OperationFilter<FileResponseTypeFilter>();
c.OperationFilter<OptionalParametersFilter>();
c.OperationFilter<ArrayInQueryParametersFilter>();
c.OperationFilter<FileResponseTypeFilter>();
c.OperationFilter<FileUploadOperationFilter>();
c.SchemaFilter<EnumSchemaFilter>();
c.SchemaFilter<NewtonsoftJsonIgnoreFilter>();
c.SchemaGeneratorOptions.UseAllOfToExtendReferenceSchemas = true;

// Use method name as operation ID, i.e. ApiAccount.GetOrganization instead of /storefrontapi/account/organization (will be treated as just organization method)
c.CustomOperationIds(apiDesc => apiDesc.TryGetMethodInfo(out var methodInfo) ? methodInfo.Name : null);

// To avoid errors with repeating type names
c.CustomSchemaIds(type => (Attribute.GetCustomAttribute(type, typeof(SwaggerSchemaIdAttribute)) as SwaggerSchemaIdAttribute)?.Id ?? type.FriendlyId());
});
services.AddSwaggerGenNewtonsoftSupport();

services.AddResponseCompression();

Expand Down Expand Up @@ -421,7 +426,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
});

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(c => c.RouteTemplate = "docs/{documentName}/docs.json");
app.UseSwagger(c =>
{
var options = app.ApplicationServices.GetService<IOptions<SwaggerOptions>>().Value;
c.SerializeAsV2 = options.Schema.OpenApiSpecificationVersion == OpenApiSpecificationVersion.V2;
c.RouteTemplate = "docs/{documentName}/docs.json";
});

var rewriteOptions = new RewriteOptions();
// Load IIS url rewrite rules from external file
Expand Down
1 change: 1 addition & 0 deletions VirtoCommerce.Storefront/VirtoCommerce.Storefront.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<PackageReference Include="Polly" Version="7.2.0" />
<PackageReference Include="Scrutor" Version="3.2.1" />
<PackageReference Include="StackExchange.Redis" Version="2.1.30" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.3.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="5.3.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.3.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.3.3" />
Expand Down
6 changes: 6 additions & 0 deletions VirtoCommerce.Storefront/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,11 @@
"SnapshotInLowPriorityThread": true,
"ProvideAnonymousTelemetry": true,
"FailedRequestLimit": 3
},
"Swagger": {
"Schema": {
"NameAndOrderRequestBody": true,
"OpenApiSpecificationVersion": "v3"
}
}
}