Skip to content

Commit 508eddb

Browse files
author
Adrian Hall
committed
(#48) Added proper request body linkage.
1 parent f06016c commit 508eddb

File tree

3 files changed

+518
-673
lines changed

3 files changed

+518
-673
lines changed

src/CommunityToolkit.Datasync.Server.OpenApi/DatasyncOperationTransformer.cs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public async Task TransformAsync(OpenApiOperation operation, OpenApiOperationTra
5252
return;
5353
}
5454

55+
if (actionName?.StartsWith("Replace", StringComparison.InvariantCultureIgnoreCase) == true)
56+
{
57+
await TransformReplaceAsync(operation, context, cancellationToken).ConfigureAwait(false);
58+
return;
59+
}
60+
5561
return;
5662
}
5763

@@ -101,10 +107,15 @@ internal Task TransformCreateAsync(OpenApiOperation operation, OpenApiOperationT
101107
{
102108
Type entityType = GetEntityType(context);
103109

104-
operation.Responses.AddEntityResponse(201, context.GetSchemaForType(entityType), includeConditionalHeaders: true);
110+
operation.AddRequestBody(context.GetSchemaForType(entityType));
111+
112+
operation.Responses.AddEntityResponse(StatusCodes.Status201Created,
113+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
105114
operation.Responses.AddStatusCode(StatusCodes.Status400BadRequest);
106-
operation.Responses.AddEntityResponse(409, context.GetSchemaForType(entityType), includeConditionalHeaders: true);
107-
operation.Responses.AddEntityResponse(412, context.GetSchemaForType(entityType), includeConditionalHeaders: true);
115+
operation.Responses.AddEntityResponse(StatusCodes.Status409Conflict,
116+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
117+
operation.Responses.AddEntityResponse(StatusCodes.Status412PreconditionFailed,
118+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
108119

109120
return Task.CompletedTask;
110121
}
@@ -126,9 +137,10 @@ internal Task TransformDeleteAsync(OpenApiOperation operation, OpenApiOperationT
126137
operation.Responses.AddStatusCode(StatusCodes.Status400BadRequest);
127138
operation.Responses.AddStatusCode(StatusCodes.Status404NotFound);
128139
operation.Responses.AddStatusCode(StatusCodes.Status410Gone);
129-
130-
operation.Responses.AddEntityResponse(409, context.GetSchemaForType(entityType), includeConditionalHeaders: true);
131-
operation.Responses.AddEntityResponse(412, context.GetSchemaForType(entityType), includeConditionalHeaders: true);
140+
operation.Responses.AddEntityResponse(StatusCodes.Status409Conflict,
141+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
142+
operation.Responses.AddEntityResponse(StatusCodes.Status412PreconditionFailed,
143+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
132144

133145
return Task.CompletedTask;
134146
}
@@ -153,7 +165,8 @@ internal Task TransformQueryAsync(OpenApiOperation operation, OpenApiOperationTr
153165
operation.Parameters.AddIntQueryParameter("$top", "The number of items to return", 1);
154166
operation.Parameters.AddIncludeDeletedQuery();
155167

156-
operation.Responses.AddEntityResponse(200, context.GetSchemaForType(pagedEntityType), includeConditionalHeaders: false);
168+
operation.Responses.AddEntityResponse(StatusCodes.Status200OK,
169+
context.GetSchemaForType(pagedEntityType), includeConditionalHeaders: false);
157170
operation.Responses.AddStatusCode(StatusCodes.Status400BadRequest);
158171

159172
return Task.CompletedTask;
@@ -174,11 +187,41 @@ internal Task TransformReadAsync(OpenApiOperation operation, OpenApiOperationTra
174187
operation.Parameters.AddIfNoneMatchHeader();
175188
operation.Parameters.AddIfModifiedSinceHeader();
176189

177-
operation.Responses.AddEntityResponse(200, context.GetSchemaForType(entityType), includeConditionalHeaders: true);
190+
operation.Responses.AddEntityResponse(StatusCodes.Status200OK,
191+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
178192
operation.Responses.AddStatusCode(StatusCodes.Status304NotModified);
179193
operation.Responses.AddStatusCode(StatusCodes.Status404NotFound);
180194
operation.Responses.AddStatusCode(StatusCodes.Status410Gone);
181195

182196
return Task.CompletedTask;
183197
}
198+
199+
/// <summary>
200+
/// Transforms a replace operation.
201+
/// </summary>
202+
/// <param name="operation">The operation to transform.</param>
203+
/// <param name="context">The operation transformer context.</param>
204+
/// <param name="cancellationToken">A cancellation token to observe.</param>
205+
/// <returns>A task that resolves when the operation is complete.</returns>
206+
internal Task TransformReplaceAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken)
207+
{
208+
Type entityType = GetEntityType(context);
209+
210+
operation.AddRequestBody(context.GetSchemaForType(entityType));
211+
operation.Parameters.AddIncludeDeletedQuery();
212+
operation.Parameters.AddIfMatchHeader();
213+
operation.Parameters.AddIfUnmodifiedSinceHeader();
214+
215+
operation.Responses.AddEntityResponse(StatusCodes.Status200OK,
216+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
217+
operation.Responses.AddStatusCode(StatusCodes.Status400BadRequest);
218+
operation.Responses.AddStatusCode(StatusCodes.Status404NotFound);
219+
operation.Responses.AddStatusCode(StatusCodes.Status410Gone);
220+
operation.Responses.AddEntityResponse(StatusCodes.Status409Conflict,
221+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
222+
operation.Responses.AddEntityResponse(StatusCodes.Status412PreconditionFailed,
223+
context.GetSchemaForType(entityType), includeConditionalHeaders: true);
224+
225+
return Task.CompletedTask;
226+
}
184227
}

src/CommunityToolkit.Datasync.Server.OpenApi/InternalExtensions.cs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
65
using Microsoft.AspNetCore.OpenApi;
76
using Microsoft.AspNetCore.WebUtilities;
8-
using Microsoft.Extensions.DependencyInjection;
97
using Microsoft.OpenApi.Any;
10-
using Microsoft.OpenApi.Extensions;
118
using Microsoft.OpenApi.Models;
12-
using System.Reflection;
13-
using System.Transactions;
9+
using System.Net.Mime;
1410

1511
namespace CommunityToolkit.Datasync.Server.OpenApi;
1612

@@ -19,25 +15,21 @@ namespace CommunityToolkit.Datasync.Server.OpenApi;
1915
/// </summary>
2016
internal static class InternalExtensions
2117
{
22-
private static readonly List<Type> openapiPrimitiveTypes = [
23-
typeof(bool),
24-
typeof(byte),
25-
typeof(int),
26-
typeof(uint),
27-
typeof(long),
28-
typeof(ulong),
29-
typeof(short),
30-
typeof(ushort),
31-
typeof(float),
32-
typeof(double),
33-
typeof(decimal),
34-
typeof(char),
35-
typeof(string),
36-
typeof(DateTime),
37-
typeof(DateTimeOffset),
38-
typeof(Guid),
39-
typeof(Uri)
40-
];
18+
/// <summary>
19+
/// Adds a request body to the operation.
20+
/// </summary>
21+
/// <param name="operation">The operation to modify.</param>
22+
/// <param name="bodySchema">The schema for the entity in the body.</param>
23+
internal static void AddRequestBody(this OpenApiOperation operation, OpenApiSchema bodySchema)
24+
{
25+
operation.RequestBody ??= new OpenApiRequestBody();
26+
operation.RequestBody.Content.Add(MediaTypeNames.Application.Json, new OpenApiMediaType
27+
{
28+
Schema = bodySchema
29+
});
30+
operation.RequestBody.Description = "The entity to process.";
31+
operation.RequestBody.Required = true;
32+
}
4133

4234
/// <summary>
4335
/// Adds a boolean query parameter to the operation parameters.

0 commit comments

Comments
 (0)