Skip to content

Commit 59c1f72

Browse files
committed
Demo to customize OpenAPI docs
1 parent b7a7307 commit 59c1f72

7 files changed

Lines changed: 64 additions & 2 deletions

File tree

src/Examples/JsonApiDotNetCoreExample/Controllers/NonJsonApiController.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public async Task<IActionResult> PostAsync([FromBody] string? name)
3838
[HttpPut]
3939
[EndpointDescription("Returns another greeting text.")]
4040
[ProducesResponseType<string>(StatusCodes.Status200OK, "text/plain")]
41+
[RequiresAdmin]
42+
[ExpiresOn("2030-01-01")]
4143
public IActionResult Put([FromQuery] string? name)
4244
{
4345
string result = $"Hi, {name}";
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1+
using System.ComponentModel.DataAnnotations;
12
using JsonApiDotNetCore.AtomicOperations;
23
using JsonApiDotNetCore.Configuration;
34
using JsonApiDotNetCore.Controllers;
45
using JsonApiDotNetCore.Middleware;
56
using JsonApiDotNetCore.Resources;
7+
using Microsoft.AspNetCore.Mvc;
68

79
namespace JsonApiDotNetCoreExample.Controllers;
810

911
public sealed class OperationsController(
1012
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IOperationsProcessor processor, IJsonApiRequest request,
1113
ITargetedFields targetedFields, IAtomicOperationFilter operationFilter)
12-
: JsonApiOperationsController(options, resourceGraph, loggerFactory, processor, request, targetedFields, operationFilter);
14+
: JsonApiOperationsController(options, resourceGraph, loggerFactory, processor, request, targetedFields, operationFilter)
15+
{
16+
[HttpPost]
17+
[RequiresAdmin]
18+
public override Task<IActionResult> PostOperationsAsync([Required] IList<OperationContainer> operations, CancellationToken cancellationToken)
19+
{
20+
return base.PostOperationsAsync(operations, cancellationToken);
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Reflection;
2+
using Microsoft.OpenApi;
3+
using Swashbuckle.AspNetCore.SwaggerGen;
4+
5+
namespace JsonApiDotNetCoreExample;
6+
7+
internal sealed class DynamicDocumentationOperationFilter : IOperationFilter
8+
{
9+
public void Apply(OpenApiOperation operation, OperationFilterContext context)
10+
{
11+
if (context.MethodInfo.GetCustomAttribute<RequiresAdminAttribute>() != null)
12+
{
13+
UpdateDescription(operation, "**CAUTION**: This endpoint requires admin permissions.");
14+
}
15+
16+
var expiresAtAttribute = context.MethodInfo.GetCustomAttribute<ExpiresOnAttribute>();
17+
18+
if (expiresAtAttribute != null)
19+
{
20+
UpdateDescription(operation, $"**NOTE: This endpoint will no longer be available after {expiresAtAttribute.Value:yyyy-MM-dd}.**");
21+
}
22+
}
23+
24+
private static void UpdateDescription(OpenApiOperation operation, string text)
25+
{
26+
if (string.IsNullOrEmpty(operation.Description))
27+
{
28+
operation.Description = text;
29+
}
30+
else
31+
{
32+
operation.Description += $"\n\n{text}";
33+
}
34+
}
35+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JsonApiDotNetCoreExample;
2+
3+
[AttributeUsage(AttributeTargets.Method)]
4+
internal sealed class ExpiresOnAttribute(string dateValue) : Attribute
5+
{
6+
public DateOnly Value { get; } = DateOnly.Parse(dateValue);
7+
}

src/Examples/JsonApiDotNetCoreExample/GeneratedSwagger/JsonApiDotNetCoreExample.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"tags": [
8787
"nonJsonApi"
8888
],
89-
"description": "Returns another greeting text.",
89+
"description": "Returns another greeting text.\n\n**CAUTION**: This endpoint requires admin permissions.\n\n**NOTE: This endpoint will no longer be available after 2030-01-01.**",
9090
"parameters": [
9191
{
9292
"name": "name",
@@ -153,6 +153,7 @@
153153
"operations"
154154
],
155155
"summary": "Performs multiple mutations in a linear and atomic manner.",
156+
"description": "**CAUTION**: This endpoint requires admin permissions.",
156157
"operationId": "postOperations",
157158
"requestBody": {
158159
"description": "An array of mutation operations. For syntax, see the [Atomic Operations documentation](https://jsonapi.org/ext/atomic/).",

src/Examples/JsonApiDotNetCoreExample/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.EntityFrameworkCore.Diagnostics;
1111
using Microsoft.Extensions.DependencyInjection.Extensions;
1212
using Scalar.AspNetCore;
13+
using Swashbuckle.AspNetCore.SwaggerGen;
1314

1415
[assembly: ExcludeFromCodeCoverage]
1516

@@ -32,6 +33,8 @@ static WebApplication CreateWebApplication(string[] args)
3233
// Add services to the container.
3334
ConfigureServices(builder);
3435

36+
builder.Services.AddOptions<SwaggerGenOptions>().Configure(options => options.OperationFilter<DynamicDocumentationOperationFilter>());
37+
3538
WebApplication app = builder.Build();
3639

3740
// Configure the HTTP request pipeline.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace JsonApiDotNetCoreExample;
2+
3+
[AttributeUsage(AttributeTargets.Method)]
4+
internal sealed class RequiresAdminAttribute : Attribute;

0 commit comments

Comments
 (0)