diff options
author | crupest <crupest@outlook.com> | 2020-08-23 18:15:25 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-23 18:15:25 +0800 |
commit | a9edf94e42e5288c0d46994546eef6a507768fcf (patch) | |
tree | 7edfeca01b33e2bff98f10148b371d473e73a299 | |
parent | c28848a35b0f31a59f9d02641571495822ad0db8 (diff) | |
parent | b1b10b7dda86138d020b1545b4de55b37ee793b3 (diff) | |
download | timeline-a9edf94e42e5288c0d46994546eef6a507768fcf.tar.gz timeline-a9edf94e42e5288c0d46994546eef6a507768fcf.tar.bz2 timeline-a9edf94e42e5288c0d46994546eef6a507768fcf.zip |
Merge pull request #150 from crupest/swagger
Enhance swagger docs.
-rw-r--r-- | Timeline/Controllers/TimelineController.cs | 3 | ||||
-rw-r--r-- | Timeline/Controllers/UserAvatarController.cs | 2 | ||||
-rw-r--r-- | Timeline/Helpers/DataCacheHelper.cs | 2 | ||||
-rw-r--r-- | Timeline/Startup.cs | 9 | ||||
-rw-r--r-- | Timeline/Swagger/DocumentDescriptionDocumentProcessor.cs | 55 |
5 files changed, 66 insertions, 5 deletions
diff --git a/Timeline/Controllers/TimelineController.cs b/Timeline/Controllers/TimelineController.cs index 43178ac6..90b50bbb 100644 --- a/Timeline/Controllers/TimelineController.cs +++ b/Timeline/Controllers/TimelineController.cs @@ -199,7 +199,8 @@ namespace Timeline.Controllers /// <param name="ifNoneMatch">If-None-Match header.</param>
/// <returns>The data.</returns>
[HttpGet("timelines/{name}/posts/{id}/data")]
- [ProducesResponseType(StatusCodes.Status200OK)]
+ [Produces("image/png", "image/jpeg", "image/gif", "image/webp", "application/json", "text/json")]
+ [ProducesResponseType(typeof(byte[]), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status304NotModified)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
diff --git a/Timeline/Controllers/UserAvatarController.cs b/Timeline/Controllers/UserAvatarController.cs index 32f63fc6..97c4bdb8 100644 --- a/Timeline/Controllers/UserAvatarController.cs +++ b/Timeline/Controllers/UserAvatarController.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
-using System.IO;
using System.Threading.Tasks;
using Timeline.Auth;
using Timeline.Filters;
@@ -46,6 +45,7 @@ namespace Timeline.Controllers /// <param name="ifNoneMatch">If-None-Match header.</param>
/// <returns>Avatar data.</returns>
[HttpGet("users/{username}/avatar")]
+ [Produces("image/png", "image/jpeg", "image/gif", "image/webp", "application/json", "text/json")]
[ProducesResponseType(typeof(byte[]), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status304NotModified)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
diff --git a/Timeline/Helpers/DataCacheHelper.cs b/Timeline/Helpers/DataCacheHelper.cs index 574d90b4..1ad69708 100644 --- a/Timeline/Helpers/DataCacheHelper.cs +++ b/Timeline/Helpers/DataCacheHelper.cs @@ -107,7 +107,7 @@ namespace Timeline.Helpers controller.Response.Headers.Add(ETagHeaderKey, eTagValue);
controller.Response.Headers.Add(CacheControlHeaderKey, GenerateCacheControlHeaderValue());
- return controller.StatusCode(StatusCodes.Status304NotModified);
+ return controller.StatusCode(StatusCodes.Status304NotModified, null);
}
}
diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 86bdaf54..82c231cb 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -1,6 +1,7 @@ using AutoMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@@ -11,6 +12,7 @@ using NSwag; using NSwag.Generation.Processors.Security;
using System;
using System.ComponentModel;
+using System.Net.Mime;
using System.Text.Json.Serialization;
using Timeline.Auth;
using Timeline.Configs;
@@ -50,6 +52,8 @@ namespace Timeline {
setup.InputFormatters.Add(new StringInputFormatter());
setup.InputFormatters.Add(new BytesInputFormatter());
+ setup.Filters.Add(new ConsumesAttribute(MediaTypeNames.Application.Json, "text/json"));
+ setup.Filters.Add(new ProducesAttribute(MediaTypeNames.Application.Json, "text/json"));
setup.UseApiRoutePrefix("api");
})
.AddJsonOptions(options =>
@@ -104,6 +108,7 @@ namespace Timeline document.DocumentName = "Timeline";
document.Title = "Timeline REST API Reference";
document.Version = typeof(Startup).Assembly.GetName().Version?.ToString() ?? "unknown version";
+ document.DocumentProcessors.Add(new DocumentDescriptionDocumentProcessor());
document.DocumentProcessors.Add(
new SecurityDefinitionAppender("JWT",
new OpenApiSecurityScheme
@@ -111,7 +116,7 @@ namespace Timeline Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
In = OpenApiSecurityApiKeyLocation.Header,
- Description = "Type into the textbox: Bearer {your JWT token}."
+ Description = "Create token via `/api/token/create` ."
}));
document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("JWT"));
document.OperationProcessors.Add(new DefaultDescriptionOperationProcessor());
@@ -153,7 +158,7 @@ namespace Timeline }
app.UseOpenApi();
- app.UseSwaggerUi3();
+ app.UseReDoc();
app.UseAuthentication();
app.UseAuthorization();
diff --git a/Timeline/Swagger/DocumentDescriptionDocumentProcessor.cs b/Timeline/Swagger/DocumentDescriptionDocumentProcessor.cs new file mode 100644 index 00000000..dc5ddd96 --- /dev/null +++ b/Timeline/Swagger/DocumentDescriptionDocumentProcessor.cs @@ -0,0 +1,55 @@ +using NSwag.Generation.Processors;
+using NSwag.Generation.Processors.Contexts;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Timeline.Models.Http;
+
+namespace Timeline.Swagger
+{
+ public class DocumentDescriptionDocumentProcessor : IDocumentProcessor
+ {
+ private static Dictionary<string, int> GetAllErrorCodes()
+ {
+ var errorCodes = new Dictionary<string, int>();
+
+ void RecursiveCheckErrorCode(Type type)
+ {
+ foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
+ .Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(int)))
+ {
+ var name = (type.FullName + "." + field.Name).Remove(0, typeof(ErrorCodes).FullName!.Length + 1).Replace("+", ".", StringComparison.OrdinalIgnoreCase);
+ int value = (int)field.GetRawConstantValue()!;
+ errorCodes.Add(name, value);
+ }
+
+ foreach (var nestedType in type.GetNestedTypes())
+ {
+ RecursiveCheckErrorCode(nestedType);
+ }
+ }
+
+ RecursiveCheckErrorCode(typeof(ErrorCodes));
+
+ return errorCodes;
+ }
+
+ public void Process(DocumentProcessorContext context)
+ {
+ StringBuilder description = new StringBuilder();
+ description.AppendLine("# Error Codes");
+ description.AppendLine("name | value");
+ description.AppendLine("---- | -----");
+ foreach (var (name, value) in GetAllErrorCodes())
+ {
+ description.AppendLine($"`{name}` | `{value}`");
+ }
+
+ context.Document.Info.Description = description.ToString();
+ }
+ }
+}
|