mirror of https://github.com/Squidex/squidex.git
15 changed files with 266 additions and 185 deletions
@ -0,0 +1,69 @@ |
|||||
|
// ==========================================================================
|
||||
|
// SwaggerUsage.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Reflection; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using NJsonSchema; |
||||
|
using NJsonSchema.Generation.TypeMappers; |
||||
|
using NSwag.AspNetCore; |
||||
|
using Squidex.Configurations.Identity; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Configurations.Swagger |
||||
|
{ |
||||
|
public static class SwaggerUsage |
||||
|
{ |
||||
|
public static void UseMySwagger(this IApplicationBuilder app) |
||||
|
{ |
||||
|
var options = app.ApplicationServices.GetService<IOptions<MyUrlsOptions>>().Value; |
||||
|
|
||||
|
var settings = |
||||
|
new SwaggerOwinSettings { Title = "Squidex API Specification" } |
||||
|
.ConfigurePaths() |
||||
|
.ConfigureSchemaSettings() |
||||
|
.ConfigureIdentity(options); |
||||
|
|
||||
|
app.UseSwagger(typeof(SwaggerUsage).GetTypeInfo().Assembly, settings); |
||||
|
} |
||||
|
|
||||
|
private static SwaggerOwinSettings ConfigurePaths(this SwaggerOwinSettings settings) |
||||
|
{ |
||||
|
settings.SwaggerRoute = $"{Constants.ApiPrefix}/swagger/v1/swagger.json"; |
||||
|
|
||||
|
settings.PostProcess = document => |
||||
|
{ |
||||
|
document.BasePath = Constants.ApiPrefix; |
||||
|
}; |
||||
|
|
||||
|
settings.MiddlewareBasePath = Constants.ApiPrefix; |
||||
|
|
||||
|
return settings; |
||||
|
} |
||||
|
|
||||
|
private static SwaggerOwinSettings ConfigureSchemaSettings(this SwaggerOwinSettings settings) |
||||
|
{ |
||||
|
settings.DefaultEnumHandling = EnumHandling.String; |
||||
|
settings.DefaultPropertyNameHandling = PropertyNameHandling.CamelCase; |
||||
|
|
||||
|
settings.TypeMappers = new List<ITypeMapper> |
||||
|
{ |
||||
|
new PrimitiveTypeMapper(typeof(Language), s => s.Type = JsonObjectType.String) |
||||
|
}; |
||||
|
|
||||
|
settings.DocumentProcessors.Add(new XmlTagProcessor()); |
||||
|
|
||||
|
settings.OperationProcessors.Add(new XmlTagProcessor()); |
||||
|
settings.OperationProcessors.Add(new XmlResponseTypesProcessor()); |
||||
|
|
||||
|
return settings; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
// ==========================================================================
|
||||
|
// XmlResponseTypesProcessor.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.RegularExpressions; |
||||
|
using NJsonSchema.Infrastructure; |
||||
|
using NSwag; |
||||
|
using NSwag.CodeGeneration.SwaggerGenerators.WebApi.Processors; |
||||
|
using NSwag.CodeGeneration.SwaggerGenerators.WebApi.Processors.Contexts; |
||||
|
|
||||
|
namespace Squidex.Configurations.Swagger |
||||
|
{ |
||||
|
public sealed class XmlResponseTypesProcessor : IOperationProcessor |
||||
|
{ |
||||
|
private static readonly Regex ResponseRegex = new Regex("(?<Code>[0-9]{3}) => (?<Description>.*)", RegexOptions.Compiled); |
||||
|
|
||||
|
public bool Process(OperationProcessorContext context) |
||||
|
{ |
||||
|
var returnsDescription = context.MethodInfo.GetXmlDocumentation("returns") ?? string.Empty; |
||||
|
|
||||
|
foreach (Match match in ResponseRegex.Matches(returnsDescription)) |
||||
|
{ |
||||
|
var statusCode = match.Groups["Code"].Value; |
||||
|
|
||||
|
SwaggerResponse response; |
||||
|
|
||||
|
if (!context.OperationDescription.Operation.Responses.TryGetValue(statusCode, out response)) |
||||
|
{ |
||||
|
response = new SwaggerResponse(); |
||||
|
|
||||
|
context.OperationDescription.Operation.Responses[statusCode] = response; |
||||
|
} |
||||
|
|
||||
|
response.Description = match.Groups["Description"].Value; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
// ==========================================================================
|
||||
|
// XmlTagProcessor.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Reflection; |
||||
|
using NJsonSchema.Infrastructure; |
||||
|
using NSwag.Annotations; |
||||
|
using NSwag.CodeGeneration.SwaggerGenerators.WebApi.Processors; |
||||
|
using NSwag.CodeGeneration.SwaggerGenerators.WebApi.Processors.Contexts; |
||||
|
|
||||
|
// ReSharper disable InvertIf
|
||||
|
|
||||
|
namespace Squidex.Configurations.Swagger |
||||
|
{ |
||||
|
public sealed class XmlTagProcessor : IOperationProcessor, IDocumentProcessor |
||||
|
{ |
||||
|
public void Process(DocumentProcessorContext context) |
||||
|
{ |
||||
|
foreach (var controllerType in context.ControllerTypes) |
||||
|
{ |
||||
|
var tagAttribute = |
||||
|
controllerType.GetTypeInfo().GetCustomAttribute<SwaggerTagAttribute>(); |
||||
|
|
||||
|
if (tagAttribute != null) |
||||
|
{ |
||||
|
var tag = context.Document.Tags.Find(x => x.Name == tagAttribute.Name); |
||||
|
|
||||
|
if (tag != null) |
||||
|
{ |
||||
|
var description = controllerType.GetXmlSummary(); |
||||
|
|
||||
|
if (description != null) |
||||
|
{ |
||||
|
tag.Description = tag.Description ?? string.Empty; |
||||
|
|
||||
|
if (!tag.Description.Contains(description)) |
||||
|
{ |
||||
|
tag.Description += "\n\n" + description; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool Process(OperationProcessorContext context) |
||||
|
{ |
||||
|
var tagAttribute = |
||||
|
context.MethodInfo.DeclaringType.GetTypeInfo().GetCustomAttribute<SwaggerTagAttribute>(); |
||||
|
|
||||
|
if (tagAttribute != null) |
||||
|
{ |
||||
|
context.OperationDescription.Operation.Tags.Clear(); |
||||
|
context.OperationDescription.Operation.Tags.Add(tagAttribute.Name); |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,123 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// SwaggerUsage.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Globalization; |
|
||||
using System.Linq; |
|
||||
using System.Reflection; |
|
||||
using Microsoft.AspNetCore.Builder; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using NJsonSchema; |
|
||||
using NJsonSchema.Generation.TypeMappers; |
|
||||
using NSwag; |
|
||||
using NSwag.AspNetCore; |
|
||||
using NSwag.CodeGeneration.SwaggerGenerators.WebApi; |
|
||||
using NSwag.CodeGeneration.SwaggerGenerators.WebApi.Processors; |
|
||||
using NSwag.CodeGeneration.SwaggerGenerators.WebApi.Processors.Contexts; |
|
||||
using Squidex.Configurations.Identity; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Modules.Api; |
|
||||
using Squidex.Pipeline; |
|
||||
|
|
||||
namespace Squidex.Configurations.Web |
|
||||
{ |
|
||||
public static class SwaggerUsage |
|
||||
{ |
|
||||
public sealed class DescriptionResponseTypeAttributeProcessor : IOperationProcessor |
|
||||
{ |
|
||||
private readonly WebApiToSwaggerGeneratorSettings settings; |
|
||||
|
|
||||
public DescriptionResponseTypeAttributeProcessor(WebApiToSwaggerGeneratorSettings settings) |
|
||||
{ |
|
||||
this.settings = settings; |
|
||||
} |
|
||||
|
|
||||
public bool Process(OperationProcessorContext context) |
|
||||
{ |
|
||||
context.OperationDescription.Operation.Responses.Remove("200"); |
|
||||
|
|
||||
var responseTypes = |
|
||||
context.MethodInfo.GetCustomAttributes<DescribedResponseTypeAttribute>().ToList(); |
|
||||
|
|
||||
responseTypes.Add(new DescribedResponseTypeAttribute(500, typeof(ErrorDto), "Operation failed.")); |
|
||||
|
|
||||
foreach (var attribute in responseTypes) |
|
||||
{ |
|
||||
var responseType = attribute.Type; |
|
||||
|
|
||||
var typeDescription = |
|
||||
JsonObjectTypeDescription.FromType(responseType, |
|
||||
context.MethodInfo.ReturnParameter?.GetCustomAttributes(), settings.DefaultEnumHandling); |
|
||||
|
|
||||
var responseCode = attribute.StatusCode.ToString(CultureInfo.InvariantCulture); |
|
||||
var response = new SwaggerResponse { Description = attribute.Description }; |
|
||||
|
|
||||
if (IsVoidResponse(responseType) == false) |
|
||||
{ |
|
||||
response.IsNullableRaw = typeDescription.IsNullable; |
|
||||
response.Schema = context.SwaggerGenerator.GenerateAndAppendSchemaFromType(responseType, typeDescription.IsNullable, null); |
|
||||
} |
|
||||
|
|
||||
context.OperationDescription.Operation.Responses[responseCode] = response; |
|
||||
|
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
private static bool IsVoidResponse(Type returnType) |
|
||||
{ |
|
||||
return returnType == null || returnType == typeof(void); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static void UseMySwagger(this IApplicationBuilder app) |
|
||||
{ |
|
||||
var options = app.ApplicationServices.GetService<IOptions<MyUrlsOptions>>().Value; |
|
||||
|
|
||||
var settings = |
|
||||
new SwaggerOwinSettings { Title = "Squidex API Specification" } |
|
||||
.ConfigurePaths() |
|
||||
.ConfigureSchemaSettings() |
|
||||
.ConfigureIdentity(options); |
|
||||
|
|
||||
app.UseSwagger(typeof(SwaggerUsage).GetTypeInfo().Assembly, settings); |
|
||||
} |
|
||||
|
|
||||
private static SwaggerOwinSettings ConfigurePaths(this SwaggerOwinSettings settings) |
|
||||
{ |
|
||||
settings.SwaggerRoute = $"{Constants.ApiPrefix}/swagger/v1/swagger.json"; |
|
||||
|
|
||||
settings.PostProcess = document => |
|
||||
{ |
|
||||
document.BasePath = Constants.ApiPrefix; |
|
||||
}; |
|
||||
|
|
||||
settings.MiddlewareBasePath = Constants.ApiPrefix; |
|
||||
|
|
||||
return settings; |
|
||||
} |
|
||||
|
|
||||
private static SwaggerOwinSettings ConfigureSchemaSettings(this SwaggerOwinSettings settings) |
|
||||
{ |
|
||||
settings.DefaultEnumHandling = EnumHandling.String; |
|
||||
settings.DefaultPropertyNameHandling = PropertyNameHandling.CamelCase; |
|
||||
|
|
||||
settings.TypeMappers = new List<ITypeMapper> |
|
||||
{ |
|
||||
new PrimitiveTypeMapper(typeof(Language), s => s.Type = JsonObjectType.String) |
|
||||
}; |
|
||||
|
|
||||
settings.OperationProcessors.Add(new DescriptionResponseTypeAttributeProcessor(settings)); |
|
||||
|
|
||||
return settings; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// DescribedResponseTypeAttribute.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using Microsoft.AspNetCore.Mvc; |
|
||||
|
|
||||
namespace Squidex.Pipeline |
|
||||
{ |
|
||||
public sealed class DescribedResponseTypeAttribute : ProducesResponseTypeAttribute |
|
||||
{ |
|
||||
public string Description { get; } |
|
||||
|
|
||||
public DescribedResponseTypeAttribute(int statusCode, string description = null) |
|
||||
: base(typeof(void), statusCode) |
|
||||
{ |
|
||||
Description = description; |
|
||||
} |
|
||||
|
|
||||
public DescribedResponseTypeAttribute(int statusCode, Type type, string description = null) |
|
||||
: base(type, statusCode) |
|
||||
{ |
|
||||
Description = description; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue