Skip to content

Commit f7f2689

Browse files
authored
Merge pull request #237 from microsoft/fix/requestBodyAndResponseRepresentationForRefOperations
Fix request body and response representation for ref POST operations
2 parents 6ac465d + 216c486 commit f7f2689

28 files changed

+966
-1933
lines changed

src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,32 @@ internal static class Constants
108108
/// <summary>
109109
/// Name used for reference update.
110110
/// </summary>
111-
public static string ReferenceUpdateSchemaName = "ReferenceUpdateSchema";
111+
public static string ReferenceUpdateSchemaName = "ReferenceUpdate";
112+
112113

114+
/// <summary>
115+
/// Name used for reference update.
116+
/// </summary>
117+
public static string ReferenceCreateSchemaName = "ReferenceCreate";
118+
119+
/// <summary>
120+
/// Name used for reference request POST body.
121+
/// </summary>
122+
public static string ReferencePostRequestBodyName = "refPostBody";
123+
124+
/// <summary>
125+
/// Name used for reference request PUT body.
126+
/// </summary>
127+
public static string ReferencePutRequestBodyName = "refPutBody";
128+
113129
/// <summary>
114130
/// The odata type name.
115131
/// </summary>
116132
public static string OdataType = "@odata.type";
133+
134+
/// <summary>
135+
/// The odata id.
136+
/// </summary>
137+
public static string OdataId = "@odata.id";
117138
}
118139
}

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public static OpenApiComponents CreateComponents(this ODataContext context)
2828
// "components": {
2929
// "schemas": …,
3030
// "parameters": …,
31-
// "responses": …
31+
// "responses": …,
32+
// "requestBodies": …
3233
// }
3334
return new OpenApiComponents
3435
{
@@ -45,13 +46,15 @@ public static OpenApiComponents CreateComponents(this ODataContext context)
4546
// It allows defining responses that can be reused across operations of the service.
4647
Responses = context.CreateResponses(),
4748

48-
// Make others as null.
49-
RequestBodies = null,
49+
// The value of requestBodies is a map of RequestBody Objects.
50+
// It allows refining request bodies that can be reused across operations of the service.
51+
RequestBodies = context.CreateRequestBodies(),
5052

5153
Examples = context.CreateExamples(),
5254

5355
SecuritySchemes = context.CreateSecuritySchemes(),
5456

57+
// Make others as null.
5558
Links = null,
5659

5760
Callbacks = null,

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,90 @@ public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IE
8585

8686
return requestBody;
8787
}
88+
89+
/// <summary>
90+
/// Create a dictionary of <see cref="OpenApiRequestBody"/> indexed by ref name.
91+
/// </summary>
92+
/// <param name="context">The OData context.</param>
93+
/// <returns>The created dictionary of <see cref="OpenApiRequestBody"/> indexed by ref name</returns>
94+
public static IDictionary<string, OpenApiRequestBody> CreateRequestBodies(this ODataContext context)
95+
{
96+
Utils.CheckArgumentNull(context, nameof(context));
97+
98+
return new Dictionary<string, OpenApiRequestBody>
99+
{
100+
{
101+
Constants.ReferencePostRequestBodyName,
102+
CreateRefPostRequestBody()
103+
},
104+
{
105+
Constants.ReferencePutRequestBodyName,
106+
CreateRefPutRequestBody()
107+
}
108+
};
109+
}
110+
111+
/// <summary>
112+
/// Create a <see cref="OpenApiRequestBody"/> to be reused across ref POST operations
113+
/// </summary>
114+
/// <returns>The created <see cref="OpenApiRequestBody"/></returns>
115+
private static OpenApiRequestBody CreateRefPostRequestBody()
116+
{
117+
OpenApiSchema schema = new()
118+
{
119+
UnresolvedReference = true,
120+
Reference = new OpenApiReference
121+
{
122+
Type = ReferenceType.Schema,
123+
Id = Constants.ReferenceCreateSchemaName
124+
}
125+
};
126+
return new OpenApiRequestBody
127+
{
128+
Required = true,
129+
Description = "New navigation property ref value",
130+
Content = new Dictionary<string, OpenApiMediaType>
131+
{
132+
{
133+
Constants.ApplicationJsonMediaType, new OpenApiMediaType
134+
{
135+
Schema = schema
136+
}
137+
}
138+
}
139+
};
140+
}
141+
142+
/// <summary>
143+
/// Create a <see cref="OpenApiRequestBody"/> to be reused across ref PUT operations
144+
/// </summary>
145+
/// <returns>The created <see cref="OpenApiRequestBody"/></returns>
146+
private static OpenApiRequestBody CreateRefPutRequestBody()
147+
{
148+
OpenApiSchema schema = new()
149+
{
150+
UnresolvedReference = true,
151+
Reference = new OpenApiReference
152+
{
153+
Type = ReferenceType.Schema,
154+
Id = Constants.ReferenceUpdateSchemaName
155+
}
156+
};
157+
158+
return new OpenApiRequestBody
159+
{
160+
Required = true,
161+
Description = "New navigation property ref values",
162+
Content = new Dictionary<string, OpenApiMediaType>
163+
{
164+
{
165+
Constants.ApplicationJsonMediaType, new OpenApiMediaType
166+
{
167+
Schema = schema
168+
}
169+
}
170+
}
171+
};
172+
}
88173
}
89174
}

src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,27 @@ public static IDictionary<string, OpenApiSchema> CreateSchemas(this ODataContext
9696
if(context.HasAnyNonContainedCollections())
9797
{
9898
schemas[$"String{Constants.CollectionSchemaSuffix}"] = CreateCollectionSchema(context, new OpenApiSchema { Type = "string" }, "string");
99-
schemas[Constants.ReferenceUpdateSchemaName] = new()
100-
{
101-
Type = "object",
102-
Properties = new Dictionary<string, OpenApiSchema>
99+
}
100+
101+
schemas[Constants.ReferenceUpdateSchemaName] = new()
102+
{
103+
Type = "object",
104+
Properties = new Dictionary<string, OpenApiSchema>
103105
{
104-
{"@odata.id", new OpenApiSchema { Type = "string", Nullable = false }},
106+
{Constants.OdataId, new OpenApiSchema { Type = "string", Nullable = false }},
105107
{Constants.OdataType, new OpenApiSchema { Type = "string", Nullable = true }},
106108
}
107-
};
108-
}
109+
};
110+
111+
schemas[Constants.ReferenceCreateSchemaName] = new()
112+
{
113+
Type = "object",
114+
Properties = new Dictionary<string, OpenApiSchema>
115+
{
116+
{Constants.OdataId, new OpenApiSchema { Type = "string", Nullable = false }}
117+
},
118+
AdditionalProperties = new OpenApiSchema { Type = "object" }
119+
};
109120

110121
return schemas;
111122
}

src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<TargetFrameworks>netstandard2.0</TargetFrameworks>
1616
<PackageId>Microsoft.OpenApi.OData</PackageId>
1717
<SignAssembly>true</SignAssembly>
18-
<Version>1.0.11-preview4</Version>
18+
<Version>1.0.11-preview5</Version>
1919
<Description>This package contains the codes you need to convert OData CSDL to Open API Document of Model.</Description>
2020
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
2121
<PackageTags>Microsoft OpenApi OData EDM</PackageTags>
@@ -26,6 +26,7 @@
2626
- Add error ranges for OData actions when ErrorResponsesAsDefault is set to false #218
2727
- Fixes missing bound operations on some navigation property paths #201
2828
- Provides support for using success status code range 2XX #153
29+
- Fixes request body and response representation for ref POST and PUT operations #228
2930
- Adds discriminator object to complex types which have derived types #233
3031
- Adds @odata.type property and makes this a required property in schemas that have discriminator objects #243
3132
</PackageReleaseNotes>

src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using System.Collections.Generic;
77
using System.Linq;
8+
using Microsoft.OData.Edm;
89
using Microsoft.OpenApi.Models;
910
using Microsoft.OpenApi.OData.Common;
1011
using Microsoft.OpenApi.OData.Generator;
@@ -38,24 +39,13 @@ protected override void SetBasicInfo(OpenApiOperation operation)
3839
/// <inheritdoc/>
3940
protected override void SetRequestBody(OpenApiOperation operation)
4041
{
41-
OpenApiSchema schema = new OpenApiSchema
42-
{
43-
Type = "object",
44-
AdditionalProperties = new OpenApiSchema { Type = "object" }
45-
};
46-
4742
operation.RequestBody = new OpenApiRequestBody
4843
{
49-
Required = true,
50-
Description = "New navigation property ref value",
51-
Content = new Dictionary<string, OpenApiMediaType>
44+
UnresolvedReference = true,
45+
Reference = new OpenApiReference
5246
{
53-
{
54-
Constants.ApplicationJsonMediaType, new OpenApiMediaType
55-
{
56-
Schema = schema
57-
}
58-
}
47+
Type = ReferenceType.RequestBody,
48+
Id = Constants.ReferencePostRequestBodyName
5949
}
6050
};
6151

@@ -65,29 +55,11 @@ protected override void SetRequestBody(OpenApiOperation operation)
6555
/// <inheritdoc/>
6656
protected override void SetResponses(OpenApiOperation operation)
6757
{
68-
OpenApiSchema schema = new OpenApiSchema
69-
{
70-
Type = "object"
71-
};
72-
7358
operation.Responses = new OpenApiResponses
7459
{
7560
{
76-
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode201,
77-
new OpenApiResponse
78-
{
79-
Description = "Created navigation property link.",
80-
Content = new Dictionary<string, OpenApiMediaType>
81-
{
82-
{
83-
Constants.ApplicationJsonMediaType,
84-
new OpenApiMediaType
85-
{
86-
Schema = schema
87-
}
88-
}
89-
}
90-
}
61+
Constants.StatusCode204,
62+
new OpenApiResponse { Description = "Success" }
9163
}
9264
};
9365

src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,11 @@ protected override void SetRequestBody(OpenApiOperation operation)
4040
{
4141
operation.RequestBody = new OpenApiRequestBody
4242
{
43-
Required = true,
44-
Description = "New navigation property ref values",
45-
Content = new Dictionary<string, OpenApiMediaType>
46-
{
47-
{
48-
Constants.ApplicationJsonMediaType, new OpenApiMediaType
49-
{
50-
Schema = GetOpenApiSchema()
51-
}
52-
}
43+
UnresolvedReference = true,
44+
Reference = new OpenApiReference
45+
{
46+
Type = ReferenceType.RequestBody,
47+
Id = Constants.ReferencePutRequestBodyName
5348
}
5449
};
5550

@@ -59,7 +54,15 @@ protected override void SetRequestBody(OpenApiOperation operation)
5954
/// <inheritdoc/>
6055
protected override void SetResponses(OpenApiOperation operation)
6156
{
62-
operation.AddErrorResponses(Context.Settings, true, GetOpenApiSchema());
57+
operation.Responses = new OpenApiResponses
58+
{
59+
{
60+
Constants.StatusCode204,
61+
new OpenApiResponse { Description = "Success" }
62+
}
63+
};
64+
65+
operation.AddErrorResponses(Context.Settings, false);
6366
base.SetResponses(operation);
6467
}
6568

@@ -90,18 +93,5 @@ protected override void AppendCustomParameters(OpenApiOperation operation)
9093
AppendCustomParameters(operation, Restriction.UpdateRestrictions.CustomQueryOptions, ParameterLocation.Query);
9194
}
9295
}
93-
94-
private OpenApiSchema GetOpenApiSchema()
95-
{
96-
return new()
97-
{
98-
UnresolvedReference = true,
99-
Reference = new OpenApiReference
100-
{
101-
Id = Constants.ReferenceUpdateSchemaName,
102-
Type = ReferenceType.Schema
103-
},
104-
};
105-
}
10696
}
10797
}

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiComponentsGeneratorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void CreateComponentsReturnsForEmptyModel()
3838
Assert.NotNull(components.Schemas);
3939
Assert.NotNull(components.Parameters);
4040
Assert.NotNull(components.Responses);
41-
Assert.Null(components.RequestBodies);
41+
Assert.NotNull(components.RequestBodies);
4242
}
4343
}
4444
}

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiRequestBodyGeneratorTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,21 @@ public void CreateRequestBodyForActionReturnCorrectRequestBody()
150150
Assert.Equal("param", parameter.Key);
151151
Assert.Equal("string", parameter.Value.Type);
152152
}
153+
154+
[Fact]
155+
public void CreateRefRequestBodies()
156+
{
157+
// Arrange
158+
ODataContext context = new ODataContext(_model);
159+
160+
// Act
161+
var requestBodies = context.CreateRequestBodies();
162+
requestBodies.TryGetValue(Common.Constants.ReferencePostRequestBodyName, out Models.OpenApiRequestBody refPostBody);
163+
164+
// Assert
165+
Assert.NotNull(refPostBody);
166+
Assert.Equal("New navigation property ref value", refPostBody.Description);
167+
Assert.Equal(Common.Constants.ReferenceCreateSchemaName, refPostBody.Content.First().Value.Schema.Reference.Id);
168+
}
153169
}
154170
}

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,30 @@ public void CreatesCollectionResponseSchema()
5959
Assert.Equal("string", stringCollectionResponse.Properties["value"].Items.Type);
6060
}
6161

62+
[Fact]
63+
public void CreatesRefRequestBodySchema()
64+
{
65+
// Arrange
66+
IEdmModel model = EdmModelHelper.TripServiceModel;
67+
OpenApiConvertSettings settings = new()
68+
{
69+
EnableOperationId = true,
70+
EnablePagination = true,
71+
};
72+
ODataContext context = new(model, settings);
73+
74+
// Act & Assert
75+
var schemas = context.CreateSchemas();
76+
77+
schemas.TryGetValue(Constants.ReferenceCreateSchemaName, out OpenApiSchema refRequestBody);
78+
79+
Assert.NotNull(refRequestBody);
80+
Assert.Equal("object", refRequestBody.Type);
81+
Assert.Equal(Constants.OdataId, refRequestBody.Properties.First().Key);
82+
Assert.Equal("string", refRequestBody.Properties.First().Value.Type);
83+
Assert.Equal("object", refRequestBody.AdditionalProperties.Type);
84+
}
85+
6286
#region StructuredTypeSchema
6387
[Fact]
6488
public void CreateStructuredTypeSchemaThrowArgumentNullContext()

0 commit comments

Comments
 (0)