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