From 962634462404c138190aa0cb05385917743e80f6 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Wed, 24 Aug 2022 16:30:48 +0300 Subject: [PATCH 1/7] Eliminate duplicated request bodies for actions --- .../Edm/EdmModelExtensions.cs | 23 ++++++++++++++++++- .../Generator/OpenApiRequestBodyGenerator.cs | 13 +++++++++-- .../Operation/EdmActionOperationHandler.cs | 20 +++++++++++++--- .../PublicAPI.Unshipped.txt | 1 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index e758e759..eb4ca5ba 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -200,7 +200,28 @@ public static bool IsOperationOverload(this IEdmModel model, IEdmOperation opera } /// - /// Check whether the operaiton import is overload in the model. + /// Checks whether operation targets singleton and entityset of the same type. + /// + /// The Edm model. + /// + /// The test operations. + public static bool OperationTargetsMultiplePaths(this IEdmModel model, IEdmOperation operation) + { + Utils.CheckArgumentNull(model, nameof(model)); + Utils.CheckArgumentNull(operation, nameof(operation)); + + if (!operation.Parameters.Any()) + return false; + + IEdmTypeReference bindingParameterType = operation.Parameters.First().Type; + + return model.EntityContainer.EntitySets().Select(x => x.EntityType()) + .Concat(model.EntityContainer.Singletons().Select(x => x.EntityType())) + .Where(x => x.FullName == bindingParameterType.FullName).Count() > 1; + } + + /// + /// Check whether the operation import is overload in the model. /// /// The Edm model. /// The test operations. diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs index fb7756ec..6d523a2f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs @@ -95,17 +95,26 @@ public static IDictionary CreateRequestBodies(this O { Utils.CheckArgumentNull(context, nameof(context)); - return new Dictionary + Dictionary requestBodies = new() { { Constants.ReferencePostRequestBodyName, - CreateRefPostRequestBody() + CreateRefPostRequestBody() }, { Constants.ReferencePutRequestBodyName, CreateRefPutRequestBody() } }; + + // add request bodies for actions targeting multiple related paths + foreach (IEdmAction action in context.Model.SchemaElements.OfType() + .Where(action => context.Model.OperationTargetsMultiplePaths(action))) + { + requestBodies.Add($"{action.Name}RequestBody", context.CreateRequestBody(action)); + } + + return requestBodies; } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs index 1844181b..71f4d834 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs @@ -37,10 +37,24 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - IEdmAction action = EdmOperation as IEdmAction; - if (action != null) + if (EdmOperation is IEdmAction action) { - operation.RequestBody = Context.CreateRequestBody(action); + if (Context.Model.OperationTargetsMultiplePaths(action)) + { + operation.RequestBody = new OpenApiRequestBody + { + UnresolvedReference = true, + Reference = new OpenApiReference + { + Type = ReferenceType.RequestBody, + Id = $"{action.Name}RequestBody" + } + }; + } + else + { + operation.RequestBody = Context.CreateRequestBody(action); + } } base.SetRequestBody(operation); diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index e9db1445..81c31912 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -30,6 +30,7 @@ Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.List = 1 -> Microsoft.OpenApi Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.ReadByKey = 0 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Update = 3 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey static Microsoft.OpenApi.OData.Common.OpenApiOperationExtensions.AddErrorResponses(this Microsoft.OpenApi.Models.OpenApiOperation operation, Microsoft.OpenApi.OData.OpenApiConvertSettings settings, bool addNoContent = false, Microsoft.OpenApi.Models.OpenApiSchema schema = null) -> void +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.OperationTargetsMultiplePaths(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> bool Microsoft.OpenApi.OData.Edm.IODataPathProvider Microsoft.OpenApi.OData.Edm.IODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement element) -> bool From dddfb343743641829f7589a059fe1fef94a67f73 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Fri, 2 Sep 2022 21:05:51 +0300 Subject: [PATCH 2/7] Eliminate duplicated responses for actions and functions --- .../Generator/OpenApiResponseGenerator.cs | 133 ++++++++++-------- .../EdmOperationImportOperationHandler.cs | 2 +- .../Operation/EdmOperationOperationHandler.cs | 2 +- .../OpenApiResponseGeneratorTests.cs | 44 ++---- .../Resources/TripService.OpenApi.V2.json | 12 +- .../Resources/TripService.OpenApi.V2.yaml | 12 +- .../Resources/TripService.OpenApi.json | 12 +- .../Resources/TripService.OpenApi.yaml | 12 +- 8 files changed, 114 insertions(+), 115 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index 813a10c7..7edae184 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -107,6 +107,12 @@ public static IDictionary CreateResponses(this ODataCon if(context.HasAnyNonContainedCollections()) responses[$"String{Constants.CollectionSchemaSuffix}"] = CreateCollectionResponse("String"); + foreach (IEdmOperation operation in context.Model.SchemaElements.OfType() + .Where(op => context.Model.OperationTargetsMultiplePaths(op))) + { + responses[$"{operation.Name}Response"] = context.CreateOperationResponse(operation); + } + return responses; } @@ -115,15 +121,13 @@ public static IDictionary CreateResponses(this ODataCon /// /// The OData context. /// The Edm operation import. - /// The OData path. /// The created . - public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport, ODataPath path) + public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(operationImport, nameof(operationImport)); - Utils.CheckArgumentNull(path, nameof(path)); - return context.CreateResponses(operationImport.Operation, path); + return context.CreateResponses(operationImport.Operation); } /// @@ -131,13 +135,11 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp /// /// The OData context. /// The Edm operation. - /// The OData path. /// The created . - public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation, ODataPath path) + public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(operation, nameof(operation)); - Utils.CheckArgumentNull(path, nameof(path)); OpenApiResponses responses = new(); @@ -145,56 +147,89 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp { responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse()); } + else if (context.Model.OperationTargetsMultiplePaths(operation) ) + { + responses.Add( + context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + new OpenApiResponse + { + UnresolvedReference = true, + Reference = new OpenApiReference() + { + Type = ReferenceType.Response, + Id = $"{operation.Name}Response" + } + } + ); + } else { - OpenApiSchema schema; - if (operation.ReturnType.IsCollection()) + OpenApiResponse response = context.CreateOperationResponse(operation); + responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response); + } + + if (context.Settings.ErrorResponsesAsDefault) + { + responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + } + else + { + responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse()); + responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse()); + } + + return responses; + } + + public static OpenApiResponse CreateOperationResponse(this ODataContext context, IEdmOperation operation) + { + OpenApiSchema schema; + if (operation.ReturnType.IsCollection()) + { + schema = new OpenApiSchema { - // Get the entity type of the previous segment - IEdmEntityType entityType = path.Segments.Reverse().Skip(1)?.Take(1)?.FirstOrDefault()?.EntityType; - schema = new OpenApiSchema - { - Title = entityType == null ? null : $"Collection of {entityType.Name}", - Type = "object", - Properties = new Dictionary + Title = operation.ReturnType.Definition.AsElementType() is not IEdmEntityType entityType + ? null : $"Collection of {entityType.Name}", + Type = "object", + Properties = new Dictionary { { "value", context.CreateEdmTypeSchema(operation.ReturnType) } } - }; - } - else if (operation.ReturnType.IsPrimitive()) + }; + } + else if (operation.ReturnType.IsPrimitive()) + { + // A property or operation response that is of a primitive type is represented as an object with a single name/value pair, + // whose name is value and whose value is a primitive value. + schema = new OpenApiSchema { - // A property or operation response that is of a primitive type is represented as an object with a single name/value pair, - // whose name is value and whose value is a primitive value. - schema = new OpenApiSchema - { - Type = "object", - Properties = new Dictionary + Type = "object", + Properties = new Dictionary { { "value", context.CreateEdmTypeSchema(operation.ReturnType) } } - }; - } - else - { - schema = context.CreateEdmTypeSchema(operation.ReturnType); - } + }; + } + else + { + schema = context.CreateEdmTypeSchema(operation.ReturnType); + } - string mediaType = Constants.ApplicationJsonMediaType; - if (operation.ReturnType.AsPrimitive()?.PrimitiveKind() == EdmPrimitiveTypeKind.Stream) - { - // Responses of types Edm.Stream should be application/octet-stream - mediaType = Constants.ApplicationOctetStreamMediaType; - } + string mediaType = Constants.ApplicationJsonMediaType; + if (operation.ReturnType.AsPrimitive()?.PrimitiveKind() == EdmPrimitiveTypeKind.Stream) + { + // Responses of types Edm.Stream should be application/octet-stream + mediaType = Constants.ApplicationOctetStreamMediaType; + } - OpenApiResponse response = new() - { - Description = "Success", - Content = new Dictionary + OpenApiResponse response = new() + { + Description = "Success", + Content = new Dictionary { { mediaType, @@ -204,21 +239,9 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp } } } - }; - responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response); - } - - if (context.Settings.ErrorResponsesAsDefault) - { - responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); - } - else - { - responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse()); - responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse()); - } + }; - return responses; + return response; } private static OpenApiResponse CreateCollectionResponse(IEdmStructuredType structuredType) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs index 13ee7af7..afdc2f9e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs @@ -77,7 +77,7 @@ protected override void SetResponses(OpenApiOperation operation) // describing the structure of the success response by referencing an appropriate schema // in the global schemas. In addition, it contains a default name/value pair for // the OData error response referencing the global responses. - operation.Responses = Context.CreateResponses(EdmOperationImport, Path); + operation.Responses = Context.CreateResponses(EdmOperationImport); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs index 09599d37..095ab417 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs @@ -167,7 +167,7 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.Responses = Context.CreateResponses(EdmOperation, Path); + operation.Responses = Context.CreateResponses(EdmOperation); base.SetResponses(operation); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiResponseGeneratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiResponseGeneratorTests.cs index 43407cc6..173b34d5 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiResponseGeneratorTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiResponseGeneratorTests.cs @@ -127,7 +127,7 @@ public void CreateResponseForoperationImportThrowArgumentNullContext() ODataContext context = null; // Act & Assert - Assert.Throws("context", () => context.CreateResponses(operationImport: null, path: null)); + Assert.Throws("context", () => context.CreateResponses(operationImport: null)); } [Fact] @@ -137,19 +137,7 @@ public void CreateResponseForoperationImportThrowArgumentNullOperationImport() ODataContext context = new ODataContext(EdmCoreModel.Instance); // Act & Assert - Assert.Throws("operationImport", () => context.CreateResponses(operationImport: null, path: null)); - } - - [Fact] - public void CreateResponseForoperationImportThrowArgumentNullPath() - { - // Arrange - ODataContext context = new ODataContext(EdmCoreModel.Instance); - EdmFunction function = new EdmFunction("NS", "MyFunction", EdmCoreModel.Instance.GetString(false)); - EdmFunctionImport functionImport = new EdmFunctionImport(new EdmEntityContainer("NS", "Default"), "MyFunctionImport", function); - - // Act & Assert - Assert.Throws("path", () => context.CreateResponses(operationImport: functionImport, path: null)); + Assert.Throws("operationImport", () => context.CreateResponses(operationImport: null)); } [Fact] @@ -159,7 +147,7 @@ public void CreateResponseForOperationThrowArgumentNullContext() ODataContext context = null; // Act & Assert - Assert.Throws("context", () => context.CreateResponses(operation: null, path: null)); + Assert.Throws("context", () => context.CreateResponses(operation: null)); } [Fact] @@ -169,19 +157,7 @@ public void CreateResponseForOperationThrowArgumentNullOperation() ODataContext context = new ODataContext(EdmCoreModel.Instance); // Act & Assert - Assert.Throws("operation", () => context.CreateResponses(operation: null, path: null)); - } - - [Fact] - public void CreateResponseForOperationThrowArgumentNullPath() - { - // Arrange - ODataContext context = new ODataContext(EdmCoreModel.Instance); - EdmFunction function = new EdmFunction("NS", "MyFunction", EdmCoreModel.Instance.GetString(false)); - EdmFunctionImport functionImport = new EdmFunctionImport(new EdmEntityContainer("NS", "Default"), "MyFunctionImport", function); - - // Act & Assert - Assert.Throws("path", () => context.CreateResponses(operation: function, path: null)); + Assert.Throws("operation", () => context.CreateResponses(operation: null)); } [Theory] @@ -205,14 +181,14 @@ public void CreateResponseForEdmFunctionReturnCorrectResponses(bool isFunctionIm IEdmOperationImport operationImport = model.EntityContainer.OperationImports().First(o => o.Name == operationName); Assert.NotNull(operationImport); // guard ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport)); - responses = context.CreateResponses(operationImport, path); + responses = context.CreateResponses(operationImport); } else { IEdmOperation operation = model.SchemaElements.OfType().First(o => o.Name == operationName); Assert.NotNull(operation); // guard ODataPath path = new ODataPath(new ODataOperationSegment(operation)); - responses = context.CreateResponses(operation, path); + responses = context.CreateResponses(operation); } // Assert @@ -264,7 +240,7 @@ public void CreateResponseForEdmFunctionOfStreamReturnTypeReturnsCorrectResponse IEdmOperation operation = model.SchemaElements.OfType().First(o => o.Name == operationName); Assert.NotNull(operation); // guard ODataPath path = new(new ODataOperationSegment(operation)); - responses = context.CreateResponses(operation, path); + responses = context.CreateResponses(operation); // Assert Assert.NotNull(responses); @@ -294,14 +270,14 @@ public void CreateResponseForEdmActionReturnCorrectResponses(string actionName, IEdmOperationImport operationImport = model.EntityContainer.OperationImports().First(o => o.Name == actionName); Assert.NotNull(operationImport); // guard ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport)); - responses = context.CreateResponses(operationImport, path); + responses = context.CreateResponses(operationImport); } else { IEdmOperation operation = model.SchemaElements.OfType().First(o => o.Name == actionName); Assert.NotNull(operation); // guard ODataPath path = new ODataPath(new ODataOperationSegment(operation)); - responses = context.CreateResponses(operation, path); + responses = context.CreateResponses(operation); } // Assert @@ -330,7 +306,7 @@ public void CreateResponseForEdmActionWhenErrorResponsesAsDefaultIsSet(string ac IEdmOperation operation = model.SchemaElements.OfType().First(o => o.Name == actionName); Assert.NotNull(operation); // guard ODataPath path = new(new ODataOperationSegment(operation)); - responses = context.CreateResponses(operation, path); + responses = context.CreateResponses(operation); // Assert Assert.NotNull(responses); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json index 4579ba69..60faa4b9 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json @@ -7454,7 +7454,7 @@ "200": { "description": "Success", "schema": { - "title": "Collection of Person", + "title": "Collection of Trip", "type": "object", "properties": { "value": { @@ -8898,7 +8898,7 @@ "200": { "description": "Success", "schema": { - "title": "Collection of Trip", + "title": "Collection of Person", "type": "object", "properties": { "value": { @@ -15327,7 +15327,7 @@ "200": { "description": "Success", "schema": { - "title": "Collection of Person", + "title": "Collection of Trip", "type": "object", "properties": { "value": { @@ -16001,7 +16001,7 @@ "200": { "description": "Success", "schema": { - "title": "Collection of Trip", + "title": "Collection of Person", "type": "object", "properties": { "value": { @@ -23800,7 +23800,7 @@ "200": { "description": "Success", "schema": { - "title": "Collection of Person", + "title": "Collection of Trip", "type": "object", "properties": { "value": { @@ -25446,7 +25446,7 @@ "200": { "description": "Success", "schema": { - "title": "Collection of Trip", + "title": "Collection of Person", "type": "object", "properties": { "value": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml index 7919422d..0abbca5f 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml @@ -5257,7 +5257,7 @@ paths: '200': description: Success schema: - title: Collection of Person + title: Collection of Trip type: object properties: value: @@ -6290,7 +6290,7 @@ paths: '200': description: Success schema: - title: Collection of Trip + title: Collection of Person type: object properties: value: @@ -10824,7 +10824,7 @@ paths: '200': description: Success schema: - title: Collection of Person + title: Collection of Trip type: object properties: value: @@ -11304,7 +11304,7 @@ paths: '200': description: Success schema: - title: Collection of Trip + title: Collection of Person type: object properties: value: @@ -16875,7 +16875,7 @@ paths: '200': description: Success schema: - title: Collection of Person + title: Collection of Trip type: object properties: value: @@ -18059,7 +18059,7 @@ paths: '200': description: Success schema: - title: Collection of Trip + title: Collection of Person type: object properties: value: diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json index ad962c6b..29447ba9 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json @@ -8257,7 +8257,7 @@ "content": { "application/json": { "schema": { - "title": "Collection of Person", + "title": "Collection of Trip", "type": "object", "properties": { "value": { @@ -9839,7 +9839,7 @@ "content": { "application/json": { "schema": { - "title": "Collection of Trip", + "title": "Collection of Person", "type": "object", "properties": { "value": { @@ -17091,7 +17091,7 @@ "content": { "application/json": { "schema": { - "title": "Collection of Person", + "title": "Collection of Trip", "type": "object", "properties": { "value": { @@ -17856,7 +17856,7 @@ "content": { "application/json": { "schema": { - "title": "Collection of Trip", + "title": "Collection of Person", "type": "object", "properties": { "value": { @@ -26597,7 +26597,7 @@ "content": { "application/json": { "schema": { - "title": "Collection of Person", + "title": "Collection of Trip", "type": "object", "properties": { "value": { @@ -28441,7 +28441,7 @@ "content": { "application/json": { "schema": { - "title": "Collection of Trip", + "title": "Collection of Person", "type": "object", "properties": { "value": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml index 3a6494a6..3b525416 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml @@ -5777,7 +5777,7 @@ paths: content: application/json: schema: - title: Collection of Person + title: Collection of Trip type: object properties: value: @@ -6895,7 +6895,7 @@ paths: content: application/json: schema: - title: Collection of Trip + title: Collection of Person type: object properties: value: @@ -11938,7 +11938,7 @@ paths: content: application/json: schema: - title: Collection of Person + title: Collection of Trip type: object properties: value: @@ -12466,7 +12466,7 @@ paths: content: application/json: schema: - title: Collection of Trip + title: Collection of Person type: object properties: value: @@ -18619,7 +18619,7 @@ paths: content: application/json: schema: - title: Collection of Person + title: Collection of Trip type: object properties: value: @@ -19918,7 +19918,7 @@ paths: content: application/json: schema: - title: Collection of Trip + title: Collection of Person type: object properties: value: From 6320dbbb074efb8772ca8e44758af64f2e131560 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Mon, 5 Sep 2022 15:00:11 +0300 Subject: [PATCH 3/7] Update tests --- .../Edm/EdmModelExtensions.cs | 6 +- .../Generator/OpenApiRequestBodyGenerator.cs | 4 +- .../Generator/OpenApiResponseGenerator.cs | 9 +- .../Microsoft.OpenAPI.OData.Reader.csproj | 2 +- .../Operation/EdmActionOperationHandler.cs | 28 +- .../EdmActionOperationHandlerTests.cs | 5 +- .../Resources/Multiple.Schema.OpenApi.V2.json | 22 +- .../Resources/Multiple.Schema.OpenApi.V2.yaml | 16 +- .../Resources/Multiple.Schema.OpenApi.json | 28 +- .../Resources/Multiple.Schema.OpenApi.yaml | 18 +- .../Resources/TripService.OpenApi.V2.json | 342 +++--------- .../Resources/TripService.OpenApi.V2.yaml | 248 ++------- .../Resources/TripService.OpenApi.json | 510 ++++++------------ .../Resources/TripService.OpenApi.yaml | 316 ++++------- 14 files changed, 443 insertions(+), 1111 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index eb4ca5ba..e28acdc1 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -215,9 +215,9 @@ public static bool OperationTargetsMultiplePaths(this IEdmModel model, IEdmOpera IEdmTypeReference bindingParameterType = operation.Parameters.First().Type; - return model.EntityContainer.EntitySets().Select(x => x.EntityType()) - .Concat(model.EntityContainer.Singletons().Select(x => x.EntityType())) - .Where(x => x.FullName == bindingParameterType.FullName).Count() > 1; + return model.EntityContainer.EntitySets().Select(static x => x.EntityType()) + .Concat(model.EntityContainer.Singletons().Select(static x => x.EntityType())) + .Where(x => x.FullName().Equals(bindingParameterType.FullName(), StringComparison.OrdinalIgnoreCase)).Count() > 1; } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs index 6d523a2f..04418da5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs @@ -111,7 +111,9 @@ public static IDictionary CreateRequestBodies(this O foreach (IEdmAction action in context.Model.SchemaElements.OfType() .Where(action => context.Model.OperationTargetsMultiplePaths(action))) { - requestBodies.Add($"{action.Name}RequestBody", context.CreateRequestBody(action)); + OpenApiRequestBody requestBody = context.CreateRequestBody(action); + if (requestBody != null) + requestBodies.Add($"{action.Name}RequestBody", requestBody); } return requestBodies; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index 7edae184..71e6b901 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -110,7 +110,9 @@ public static IDictionary CreateResponses(this ODataCon foreach (IEdmOperation operation in context.Model.SchemaElements.OfType() .Where(op => context.Model.OperationTargetsMultiplePaths(op))) { - responses[$"{operation.Name}Response"] = context.CreateOperationResponse(operation); + OpenApiResponse response = context.CreateOperationResponse(operation); + if (response != null) + responses[$"{operation.Name}Response"] = response; } return responses; @@ -147,7 +149,7 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp { responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse()); } - else if (context.Model.OperationTargetsMultiplePaths(operation) ) + else if (context.Model.OperationTargetsMultiplePaths(operation)) { responses.Add( context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, @@ -183,6 +185,9 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp public static OpenApiResponse CreateOperationResponse(this ODataContext context, IEdmOperation operation) { + if (operation.ReturnType == null) + return null; + OpenApiSchema schema; if (operation.ReturnType.IsCollection()) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj index be061bdc..538ad8a8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -15,7 +15,7 @@ netstandard2.0 Microsoft.OpenApi.OData true - 1.1.0-preview1 + 1.1.0-preview14 This package contains the codes you need to convert OData CSDL to Open API Document of Model. © Microsoft Corporation. All rights reserved. Microsoft OpenApi OData EDM diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs index 71f4d834..4e1da45d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs @@ -39,21 +39,25 @@ protected override void SetRequestBody(OpenApiOperation operation) { if (EdmOperation is IEdmAction action) { - if (Context.Model.OperationTargetsMultiplePaths(action)) + OpenApiRequestBody requestBody = Context.CreateRequestBody(action); + if (requestBody != null) { - operation.RequestBody = new OpenApiRequestBody + if (Context.Model.OperationTargetsMultiplePaths(action)) { - UnresolvedReference = true, - Reference = new OpenApiReference + operation.RequestBody = new OpenApiRequestBody { - Type = ReferenceType.RequestBody, - Id = $"{action.Name}RequestBody" - } - }; - } - else - { - operation.RequestBody = Context.CreateRequestBody(action); + UnresolvedReference = true, + Reference = new OpenApiReference + { + Type = ReferenceType.RequestBody, + Id = $"{action.Name}RequestBody" + } + }; + } + else + { + operation.RequestBody = requestBody; + } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs index a4e93bb6..427ed0dc 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/EdmActionOperationHandlerTests.cs @@ -47,7 +47,10 @@ public void CreateOperationForEdmActionReturnsCorrectOperation() Assert.Equal(new string[] { "UserName" }, operation.Parameters.Select(p => p.Name)); Assert.NotNull(operation.RequestBody); - Assert.Equal("Action parameters", operation.RequestBody.Description); + if (operation.RequestBody.Reference != null) + Assert.Equal("ShareTripRequestBody", operation.RequestBody.Reference.Id); + else + Assert.Equal("Action parameters", operation.RequestBody.Description); Assert.Equal(2, operation.Responses.Count); Assert.Equal(new string[] { "204", "default" }, operation.Responses.Select(e => e.Key)); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json index 9c7283a2..458fe4a8 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json @@ -584,9 +584,6 @@ ], "summary": "Invoke action Upload", "operationId": "Documents.DocumentDto.Upload", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -602,10 +599,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/Siterra.Documents.App.DTO.DocumentDto" - } + "$ref": "#/responses/UploadResponse" }, "default": { "$ref": "#/responses/error" @@ -3312,9 +3306,6 @@ ], "summary": "Invoke action Upload", "operationId": "Tasks.DocumentDto.Upload", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -3330,10 +3321,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/Siterra.Documents.App.DTO.DocumentDto" - } + "$ref": "#/responses/UploadResponse" }, "default": { "$ref": "#/responses/error" @@ -5947,6 +5935,12 @@ "schema": { "$ref": "#/definitions/StringCollectionResponse" } + }, + "UploadResponse": { + "description": "Success", + "schema": { + "$ref": "#/definitions/Siterra.Documents.App.DTO.DocumentDto" + } } }, "tags": [ diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml index 0eeef1e2..98e7737f 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml @@ -411,8 +411,6 @@ paths: - Documents.Actions summary: Invoke action Upload operationId: Documents.DocumentDto.Upload - produces: - - application/json parameters: - in: path name: Id @@ -425,9 +423,7 @@ paths: x-ms-docs-key-type: DocumentDto responses: '200': - description: Success - schema: - $ref: '#/definitions/Siterra.Documents.App.DTO.DocumentDto' + $ref: '#/responses/UploadResponse' default: $ref: '#/responses/error' x-ms-docs-operation-type: action @@ -2379,8 +2375,6 @@ paths: - Tasks.Actions summary: Invoke action Upload operationId: Tasks.DocumentDto.Upload - produces: - - application/json parameters: - in: path name: Id @@ -2393,9 +2387,7 @@ paths: x-ms-docs-key-type: DocumentDto responses: '200': - description: Success - schema: - $ref: '#/definitions/Siterra.Documents.App.DTO.DocumentDto' + $ref: '#/responses/UploadResponse' default: $ref: '#/responses/error' x-ms-docs-operation-type: action @@ -4352,6 +4344,10 @@ responses: description: Retrieved collection schema: $ref: '#/definitions/StringCollectionResponse' + UploadResponse: + description: Success + schema: + $ref: '#/definitions/Siterra.Documents.App.DTO.DocumentDto' tags: - name: Categories.CategoryDto x-ms-docs-toc-type: page diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json index 3bb1438d..bdeb9ef8 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json @@ -676,14 +676,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Siterra.Documents.App.DTO.DocumentDto" - } - } - } + "$ref": "#/components/responses/UploadResponse" }, "default": { "$ref": "#/components/responses/error" @@ -3776,14 +3769,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Siterra.Documents.App.DTO.DocumentDto" - } - } - } + "$ref": "#/components/responses/UploadResponse" }, "default": { "$ref": "#/components/responses/error" @@ -6725,6 +6711,16 @@ } } } + }, + "UploadResponse": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Siterra.Documents.App.DTO.DocumentDto" + } + } + } } }, "parameters": { diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml index 83f3bb19..b84a3a47 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml @@ -473,11 +473,7 @@ paths: x-ms-docs-key-type: DocumentDto responses: '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/Siterra.Documents.App.DTO.DocumentDto' + $ref: '#/components/responses/UploadResponse' default: $ref: '#/components/responses/error' x-ms-docs-operation-type: action @@ -2683,11 +2679,7 @@ paths: x-ms-docs-key-type: DocumentDto responses: '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/Siterra.Documents.App.DTO.DocumentDto' + $ref: '#/components/responses/UploadResponse' default: $ref: '#/components/responses/error' x-ms-docs-operation-type: action @@ -4846,6 +4838,12 @@ components: application/json: schema: $ref: '#/components/schemas/StringCollectionResponse' + UploadResponse: + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/Siterra.Documents.App.DTO.DocumentDto' parameters: top: name: $top diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json index 60faa4b9..65fee745 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json @@ -7344,15 +7344,9 @@ ], "summary": "Invoke function GetFavoriteAirline", "operationId": "Me.GetFavoriteAirline", - "produces": [ - "application/json" - ], "responses": { "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" - } + "$ref": "#/responses/GetFavoriteAirlineResponse" }, "default": { "$ref": "#/responses/error" @@ -7376,9 +7370,6 @@ ], "summary": "Invoke function GetFriendsTrips", "operationId": "Me.GetFriendsTrips", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -7452,19 +7443,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "title": "Collection of Trip", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" - } - } - } - } + "$ref": "#/responses/GetFriendsTripsResponse" }, "default": { "$ref": "#/responses/error" @@ -7488,49 +7467,17 @@ ], "summary": "Invoke action GetPeersForTrip", "operationId": "Me.GetPeersForTrip", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], + "consumes": [ ], "parameters": [ { "in": "body", "name": "body", - "description": "Action parameters", - "required": true, - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - } - } - } + "schema": { } } ], "responses": { "200": { - "description": "Success", - "schema": { - "title": "Collection of Person", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" - } - } - } - } + "$ref": "#/responses/GetPeersForTripResponse" }, "default": { "$ref": "#/responses/error" @@ -8388,29 +8335,12 @@ "summary": "Invoke action ShareTrip", "description": "Details of the shared trip.", "operationId": "Me.ShareTrip", - "consumes": [ - "application/json" - ], + "consumes": [ ], "parameters": [ { "in": "body", "name": "body", - "description": "Action parameters", - "required": true, - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - } - } - } + "schema": { } } ], "responses": { @@ -8439,9 +8369,6 @@ ], "summary": "Invoke function UpdatePersonLastName", "operationId": "Me.UpdatePersonLastName", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -8453,16 +8380,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "type": "object", - "properties": { - "value": { - "default": false, - "type": "boolean" - } - } - } + "$ref": "#/responses/UpdatePersonLastNameResponse" }, "default": { "$ref": "#/responses/error" @@ -15206,9 +15124,6 @@ ], "summary": "Invoke function GetFavoriteAirline", "operationId": "NewComePeople.Person.GetFavoriteAirline", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -15221,10 +15136,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" - } + "$ref": "#/responses/GetFavoriteAirlineResponse" }, "default": { "$ref": "#/responses/error" @@ -15241,9 +15153,6 @@ ], "summary": "Invoke function GetFriendsTrips", "operationId": "NewComePeople.Person.GetFriendsTrips", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -15325,19 +15234,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "title": "Collection of Trip", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" - } - } - } - } + "$ref": "#/responses/GetFriendsTripsResponse" }, "default": { "$ref": "#/responses/error" @@ -15361,12 +15258,7 @@ ], "summary": "Invoke action GetPeersForTrip", "operationId": "NewComePeople.Person.GetPeersForTrip", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], + "consumes": [ ], "parameters": [ { "in": "path", @@ -15379,39 +15271,12 @@ { "in": "body", "name": "body", - "description": "Action parameters", - "required": true, - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - } - } - } + "schema": { } } ], "responses": { "200": { - "description": "Success", - "schema": { - "title": "Collection of Person", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" - } - } - } - } + "$ref": "#/responses/GetPeersForTripResponse" }, "default": { "$ref": "#/responses/error" @@ -15476,9 +15341,7 @@ "summary": "Invoke action ShareTrip", "description": "Details of the shared trip.", "operationId": "NewComePeople.Person.ShareTrip", - "consumes": [ - "application/json" - ], + "consumes": [ ], "parameters": [ { "in": "path", @@ -15491,22 +15354,7 @@ { "in": "body", "name": "body", - "description": "Action parameters", - "required": true, - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - } - } - } + "schema": { } } ], "responses": { @@ -15528,9 +15376,6 @@ ], "summary": "Invoke function UpdatePersonLastName", "operationId": "NewComePeople.Person.UpdatePersonLastName", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -15550,16 +15395,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "type": "object", - "properties": { - "value": { - "default": false, - "type": "boolean" - } - } - } + "$ref": "#/responses/UpdatePersonLastNameResponse" }, "default": { "$ref": "#/responses/error" @@ -23672,9 +23508,6 @@ ], "summary": "Invoke function GetFavoriteAirline", "operationId": "People.Person.GetFavoriteAirline", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -23687,10 +23520,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" - } + "$ref": "#/responses/GetFavoriteAirlineResponse" }, "default": { "$ref": "#/responses/error" @@ -23714,9 +23544,6 @@ ], "summary": "Invoke function GetFriendsTrips", "operationId": "People.Person.GetFriendsTrips", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -23798,19 +23625,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "title": "Collection of Trip", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" - } - } - } - } + "$ref": "#/responses/GetFriendsTripsResponse" }, "default": { "$ref": "#/responses/error" @@ -23834,12 +23649,7 @@ ], "summary": "Invoke action GetPeersForTrip", "operationId": "People.Person.GetPeersForTrip", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], + "consumes": [ ], "parameters": [ { "in": "path", @@ -23852,39 +23662,12 @@ { "in": "body", "name": "body", - "description": "Action parameters", - "required": true, - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - } - } - } + "schema": { } } ], "responses": { "200": { - "description": "Success", - "schema": { - "title": "Collection of Person", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" - } - } - } - } + "$ref": "#/responses/GetPeersForTripResponse" }, "default": { "$ref": "#/responses/error" @@ -24872,9 +24655,7 @@ "summary": "Invoke action ShareTrip", "description": "Details of the shared trip.", "operationId": "People.Person.ShareTrip", - "consumes": [ - "application/json" - ], + "consumes": [ ], "parameters": [ { "in": "path", @@ -24887,22 +24668,7 @@ { "in": "body", "name": "body", - "description": "Action parameters", - "required": true, - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - } - } - } + "schema": { } } ], "responses": { @@ -24931,9 +24697,6 @@ ], "summary": "Invoke function UpdatePersonLastName", "operationId": "People.Person.UpdatePersonLastName", - "produces": [ - "application/json" - ], "parameters": [ { "in": "path", @@ -24953,16 +24716,7 @@ ], "responses": { "200": { - "description": "Success", - "schema": { - "type": "object", - "properties": { - "value": { - "default": false, - "type": "boolean" - } - } - } + "$ref": "#/responses/UpdatePersonLastNameResponse" }, "default": { "$ref": "#/responses/error" @@ -27110,6 +26864,54 @@ "schema": { "$ref": "#/definitions/StringCollectionResponse" } + }, + "GetFavoriteAirlineResponse": { + "description": "Success", + "schema": { + "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" + } + }, + "GetFriendsTripsResponse": { + "description": "Success", + "schema": { + "title": "Collection of Trip", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" + } + } + } + } + }, + "UpdatePersonLastNameResponse": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "value": { + "default": false, + "type": "boolean" + } + } + } + }, + "GetPeersForTripResponse": { + "description": "Success", + "schema": { + "title": "Collection of Person", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" + } + } + } + } } }, "tags": [ diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml index 0abbca5f..34607772 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml @@ -5178,13 +5178,9 @@ paths: - Me.Functions summary: Invoke function GetFavoriteAirline operationId: Me.GetFavoriteAirline - produces: - - application/json responses: '200': - description: Success - schema: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' + $ref: '#/responses/GetFavoriteAirlineResponse' default: $ref: '#/responses/error' deprecated: true @@ -5201,8 +5197,6 @@ paths: - Me.Functions summary: Invoke function GetFriendsTrips operationId: Me.GetFriendsTrips - produces: - - application/json parameters: - in: path name: userName @@ -5255,15 +5249,7 @@ paths: type: string responses: '200': - description: Success - schema: - title: Collection of Trip - type: object - properties: - value: - type: array - items: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' + $ref: '#/responses/GetFriendsTripsResponse' default: $ref: '#/responses/error' deprecated: true @@ -5280,36 +5266,14 @@ paths: - Me.Actions summary: Invoke action GetPeersForTrip operationId: Me.GetPeersForTrip - consumes: - - application/json - produces: - - application/json + consumes: [ ] parameters: - in: body name: body - description: Action parameters - required: true - schema: - type: object - properties: - userName: - type: string - tripId: - format: int32 - maximum: 2147483647 - minimum: -2147483648 - type: integer + schema: { } responses: '200': - description: Success - schema: - title: Collection of Person - type: object - properties: - value: - type: array - items: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' + $ref: '#/responses/GetPeersForTripResponse' default: $ref: '#/responses/error' deprecated: true @@ -5918,23 +5882,11 @@ paths: summary: Invoke action ShareTrip description: Details of the shared trip. operationId: Me.ShareTrip - consumes: - - application/json + consumes: [ ] parameters: - in: body name: body - description: Action parameters - required: true - schema: - type: object - properties: - userName: - type: string - tripId: - format: int32 - maximum: 2147483647 - minimum: -2147483648 - type: integer + schema: { } responses: '204': description: Success @@ -5954,8 +5906,6 @@ paths: - Me.Functions summary: Invoke function UpdatePersonLastName operationId: Me.UpdatePersonLastName - produces: - - application/json parameters: - in: path name: lastName @@ -5964,13 +5914,7 @@ paths: type: string responses: '200': - description: Success - schema: - type: object - properties: - value: - default: false - type: boolean + $ref: '#/responses/UpdatePersonLastNameResponse' default: $ref: '#/responses/error' deprecated: true @@ -10738,8 +10682,6 @@ paths: - NewComePeople.Functions summary: Invoke function GetFavoriteAirline operationId: NewComePeople.Person.GetFavoriteAirline - produces: - - application/json parameters: - in: path name: UserName @@ -10749,9 +10691,7 @@ paths: x-ms-docs-key-type: Person responses: '200': - description: Success - schema: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' + $ref: '#/responses/GetFavoriteAirlineResponse' default: $ref: '#/responses/error' x-ms-docs-operation-type: function @@ -10762,8 +10702,6 @@ paths: - NewComePeople.Functions summary: Invoke function GetFriendsTrips operationId: NewComePeople.Person.GetFriendsTrips - produces: - - application/json parameters: - in: path name: UserName @@ -10822,15 +10760,7 @@ paths: type: string responses: '200': - description: Success - schema: - title: Collection of Trip - type: object - properties: - value: - type: array - items: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' + $ref: '#/responses/GetFriendsTripsResponse' default: $ref: '#/responses/error' deprecated: true @@ -10847,10 +10777,7 @@ paths: - NewComePeople.Actions summary: Invoke action GetPeersForTrip operationId: NewComePeople.Person.GetPeersForTrip - consumes: - - application/json - produces: - - application/json + consumes: [ ] parameters: - in: path name: UserName @@ -10860,29 +10787,10 @@ paths: x-ms-docs-key-type: Person - in: body name: body - description: Action parameters - required: true - schema: - type: object - properties: - userName: - type: string - tripId: - format: int32 - maximum: 2147483647 - minimum: -2147483648 - type: integer + schema: { } responses: '200': - description: Success - schema: - title: Collection of Person - type: object - properties: - value: - type: array - items: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' + $ref: '#/responses/GetPeersForTripResponse' default: $ref: '#/responses/error' x-ms-docs-operation-type: action @@ -10926,8 +10834,7 @@ paths: summary: Invoke action ShareTrip description: Details of the shared trip. operationId: NewComePeople.Person.ShareTrip - consumes: - - application/json + consumes: [ ] parameters: - in: path name: UserName @@ -10937,18 +10844,7 @@ paths: x-ms-docs-key-type: Person - in: body name: body - description: Action parameters - required: true - schema: - type: object - properties: - userName: - type: string - tripId: - format: int32 - maximum: 2147483647 - minimum: -2147483648 - type: integer + schema: { } responses: '204': description: Success @@ -10962,8 +10858,6 @@ paths: - NewComePeople.Functions summary: Invoke function UpdatePersonLastName operationId: NewComePeople.Person.UpdatePersonLastName - produces: - - application/json parameters: - in: path name: UserName @@ -10978,13 +10872,7 @@ paths: type: string responses: '200': - description: Success - schema: - type: object - properties: - value: - default: false - type: boolean + $ref: '#/responses/UpdatePersonLastNameResponse' default: $ref: '#/responses/error' x-ms-docs-operation-type: function @@ -16783,8 +16671,6 @@ paths: - People.Functions summary: Invoke function GetFavoriteAirline operationId: People.Person.GetFavoriteAirline - produces: - - application/json parameters: - in: path name: UserName @@ -16794,9 +16680,7 @@ paths: x-ms-docs-key-type: Person responses: '200': - description: Success - schema: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' + $ref: '#/responses/GetFavoriteAirlineResponse' default: $ref: '#/responses/error' deprecated: true @@ -16813,8 +16697,6 @@ paths: - People.Functions summary: Invoke function GetFriendsTrips operationId: People.Person.GetFriendsTrips - produces: - - application/json parameters: - in: path name: UserName @@ -16873,15 +16755,7 @@ paths: type: string responses: '200': - description: Success - schema: - title: Collection of Trip - type: object - properties: - value: - type: array - items: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' + $ref: '#/responses/GetFriendsTripsResponse' default: $ref: '#/responses/error' deprecated: true @@ -16898,10 +16772,7 @@ paths: - People.Actions summary: Invoke action GetPeersForTrip operationId: People.Person.GetPeersForTrip - consumes: - - application/json - produces: - - application/json + consumes: [ ] parameters: - in: path name: UserName @@ -16911,29 +16782,10 @@ paths: x-ms-docs-key-type: Person - in: body name: body - description: Action parameters - required: true - schema: - type: object - properties: - userName: - type: string - tripId: - format: int32 - maximum: 2147483647 - minimum: -2147483648 - type: integer + schema: { } responses: '200': - description: Success - schema: - title: Collection of Person - type: object - properties: - value: - type: array - items: - $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' + $ref: '#/responses/GetPeersForTripResponse' default: $ref: '#/responses/error' deprecated: true @@ -17639,8 +17491,7 @@ paths: summary: Invoke action ShareTrip description: Details of the shared trip. operationId: People.Person.ShareTrip - consumes: - - application/json + consumes: [ ] parameters: - in: path name: UserName @@ -17650,18 +17501,7 @@ paths: x-ms-docs-key-type: Person - in: body name: body - description: Action parameters - required: true - schema: - type: object - properties: - userName: - type: string - tripId: - format: int32 - maximum: 2147483647 - minimum: -2147483648 - type: integer + schema: { } responses: '204': description: Success @@ -17681,8 +17521,6 @@ paths: - People.Functions summary: Invoke function UpdatePersonLastName operationId: People.Person.UpdatePersonLastName - produces: - - application/json parameters: - in: path name: UserName @@ -17697,13 +17535,7 @@ paths: type: string responses: '200': - description: Success - schema: - type: object - properties: - value: - default: false - type: boolean + $ref: '#/responses/UpdatePersonLastNameResponse' default: $ref: '#/responses/error' deprecated: true @@ -19202,6 +19034,38 @@ responses: description: Retrieved collection schema: $ref: '#/definitions/StringCollectionResponse' + GetFavoriteAirlineResponse: + description: Success + schema: + $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' + GetFriendsTripsResponse: + description: Success + schema: + title: Collection of Trip + type: object + properties: + value: + type: array + items: + $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' + UpdatePersonLastNameResponse: + description: Success + schema: + type: object + properties: + value: + default: false + type: boolean + GetPeersForTripResponse: + description: Success + schema: + title: Collection of Person + type: object + properties: + value: + type: array + items: + $ref: '#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' tags: - name: Airlines.Airline x-ms-docs-toc-type: page diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json index 29447ba9..f7b1e980 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json @@ -8129,22 +8129,7 @@ "operationId": "Me.GetFavoriteAirline", "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } + "$ref": "#/components/responses/GetFavoriteAirlineResponse" }, "default": { "$ref": "#/components/responses/error" @@ -8253,31 +8238,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "title": "Collection of Trip", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } - } - } - } + "$ref": "#/components/responses/GetFriendsTripsResponse" }, "default": { "$ref": "#/components/responses/error" @@ -8302,54 +8263,11 @@ "summary": "Invoke action GetPeersForTrip", "operationId": "Me.GetPeersForTrip", "requestBody": { - "description": "Action parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer", - "format": "int32" - } - } - } - } - }, - "required": true + "$ref": "#/components/requestBodies/GetPeersForTripRequestBody" }, "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "title": "Collection of Person", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } - } - } - } + "$ref": "#/components/responses/GetPeersForTripResponse" }, "default": { "$ref": "#/components/responses/error" @@ -9288,26 +9206,7 @@ "description": "Details of the shared trip.", "operationId": "Me.ShareTrip", "requestBody": { - "description": "Action parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer", - "format": "int32" - } - } - } - } - }, - "required": true + "$ref": "#/components/requestBodies/ShareTripRequestBody" }, "responses": { "204": { @@ -9348,20 +9247,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "value": { - "type": "boolean", - "default": false - } - } - } - } - } + "$ref": "#/components/responses/UpdatePersonLastNameResponse" }, "default": { "$ref": "#/components/responses/error" @@ -16960,22 +16846,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } + "$ref": "#/components/responses/GetFavoriteAirlineResponse" }, "default": { "$ref": "#/components/responses/error" @@ -17087,31 +16958,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "title": "Collection of Trip", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } - } - } - } + "$ref": "#/components/responses/GetFriendsTripsResponse" }, "default": { "$ref": "#/components/responses/error" @@ -17148,54 +16995,11 @@ } ], "requestBody": { - "description": "Action parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer", - "format": "int32" - } - } - } - } - }, - "required": true + "$ref": "#/components/requestBodies/GetPeersForTripRequestBody" }, "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "title": "Collection of Person", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } - } - } - } + "$ref": "#/components/responses/GetPeersForTripResponse" }, "default": { "$ref": "#/components/responses/error" @@ -17282,26 +17086,7 @@ } ], "requestBody": { - "description": "Action parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer", - "format": "int32" - } - } - } - } - }, - "required": true + "$ref": "#/components/requestBodies/ShareTripRequestBody" }, "responses": { "204": { @@ -17345,20 +17130,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "value": { - "type": "boolean", - "default": false - } - } - } - } - } + "$ref": "#/components/responses/UpdatePersonLastNameResponse" }, "default": { "$ref": "#/components/responses/error" @@ -26459,22 +26231,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } + "$ref": "#/components/responses/GetFavoriteAirlineResponse" }, "default": { "$ref": "#/components/responses/error" @@ -26593,31 +26350,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "title": "Collection of Trip", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } - } - } - } + "$ref": "#/components/responses/GetFriendsTripsResponse" }, "default": { "$ref": "#/components/responses/error" @@ -26654,54 +26387,11 @@ } ], "requestBody": { - "description": "Action parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer", - "format": "int32" - } - } - } - } - }, - "required": true + "$ref": "#/components/requestBodies/GetPeersForTripRequestBody" }, "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "title": "Collection of Person", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" - }, - { - "type": "object", - "nullable": true - } - ] - } - } - } - } - } - } + "$ref": "#/components/responses/GetPeersForTripResponse" }, "default": { "$ref": "#/components/responses/error" @@ -27818,26 +27508,7 @@ } ], "requestBody": { - "description": "Action parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userName": { - "type": "string" - }, - "tripId": { - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer", - "format": "int32" - } - } - } - } - }, - "required": true + "$ref": "#/components/requestBodies/ShareTripRequestBody" }, "responses": { "204": { @@ -27888,20 +27559,7 @@ ], "responses": { "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "value": { - "type": "boolean", - "default": false - } - } - } - } - } + "$ref": "#/components/responses/UpdatePersonLastNameResponse" }, "default": { "$ref": "#/components/responses/error" @@ -30388,6 +30046,94 @@ } } } + }, + "GetFavoriteAirlineResponse": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline" + }, + { + "type": "object", + "nullable": true + } + ] + } + } + } + }, + "GetFriendsTripsResponse": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "title": "Collection of Trip", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip" + }, + { + "type": "object", + "nullable": true + } + ] + } + } + } + } + } + } + }, + "UpdatePersonLastNameResponse": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "boolean", + "default": false + } + } + } + } + } + }, + "GetPeersForTripResponse": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "title": "Collection of Person", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" + }, + { + "type": "object", + "nullable": true + } + ] + } + } + } + } + } + } } }, "parameters": { @@ -30631,6 +30377,50 @@ } }, "required": true + }, + "ShareTripRequestBody": { + "description": "Action parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userName": { + "type": "string" + }, + "tripId": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + } + } + } + } + }, + "required": true + }, + "GetPeersForTripRequestBody": { + "description": "Action parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userName": { + "type": "string" + }, + "tripId": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer", + "format": "int32" + } + } + } + } + }, + "required": true } } }, diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml index 3b525416..8de34a8f 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml @@ -5688,14 +5688,7 @@ paths: operationId: Me.GetFavoriteAirline responses: '200': - description: Success - content: - application/json: - schema: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' - - type: object - nullable: true + $ref: '#/components/responses/GetFavoriteAirlineResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -5773,20 +5766,7 @@ paths: type: string responses: '200': - description: Success - content: - application/json: - schema: - title: Collection of Trip - type: object - properties: - value: - type: array - items: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' - - type: object - nullable: true + $ref: '#/components/responses/GetFriendsTripsResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -5804,36 +5784,10 @@ paths: summary: Invoke action GetPeersForTrip operationId: Me.GetPeersForTrip requestBody: - description: Action parameters - content: - application/json: - schema: - type: object - properties: - userName: - type: string - tripId: - maximum: 2147483647 - minimum: -2147483648 - type: integer - format: int32 - required: true + $ref: '#/components/requestBodies/GetPeersForTripRequestBody' responses: '200': - description: Success - content: - application/json: - schema: - title: Collection of Person - type: object - properties: - value: - type: array - items: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' - - type: object - nullable: true + $ref: '#/components/responses/GetPeersForTripResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -6495,20 +6449,7 @@ paths: description: Details of the shared trip. operationId: Me.ShareTrip requestBody: - description: Action parameters - content: - application/json: - schema: - type: object - properties: - userName: - type: string - tripId: - maximum: 2147483647 - minimum: -2147483648 - type: integer - format: int32 - required: true + $ref: '#/components/requestBodies/ShareTripRequestBody' responses: '204': description: Success @@ -6537,15 +6478,7 @@ paths: type: string responses: '200': - description: Success - content: - application/json: - schema: - type: object - properties: - value: - type: boolean - default: false + $ref: '#/components/responses/UpdatePersonLastNameResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -11848,14 +11781,7 @@ paths: x-ms-docs-key-type: Person responses: '200': - description: Success - content: - application/json: - schema: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' - - type: object - nullable: true + $ref: '#/components/responses/GetFavoriteAirlineResponse' default: $ref: '#/components/responses/error' x-ms-docs-operation-type: function @@ -11934,20 +11860,7 @@ paths: type: string responses: '200': - description: Success - content: - application/json: - schema: - title: Collection of Trip - type: object - properties: - value: - type: array - items: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' - - type: object - nullable: true + $ref: '#/components/responses/GetFriendsTripsResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -11973,36 +11886,10 @@ paths: type: string x-ms-docs-key-type: Person requestBody: - description: Action parameters - content: - application/json: - schema: - type: object - properties: - userName: - type: string - tripId: - maximum: 2147483647 - minimum: -2147483648 - type: integer - format: int32 - required: true + $ref: '#/components/requestBodies/GetPeersForTripRequestBody' responses: '200': - description: Success - content: - application/json: - schema: - title: Collection of Person - type: object - properties: - value: - type: array - items: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' - - type: object - nullable: true + $ref: '#/components/responses/GetPeersForTripResponse' default: $ref: '#/components/responses/error' x-ms-docs-operation-type: action @@ -12058,20 +11945,7 @@ paths: type: string x-ms-docs-key-type: Person requestBody: - description: Action parameters - content: - application/json: - schema: - type: object - properties: - userName: - type: string - tripId: - maximum: 2147483647 - minimum: -2147483648 - type: integer - format: int32 - required: true + $ref: '#/components/requestBodies/ShareTripRequestBody' responses: '204': description: Success @@ -12101,15 +11975,7 @@ paths: type: string responses: '200': - description: Success - content: - application/json: - schema: - type: object - properties: - value: - type: boolean - default: false + $ref: '#/components/responses/UpdatePersonLastNameResponse' default: $ref: '#/components/responses/error' x-ms-docs-operation-type: function @@ -18523,14 +18389,7 @@ paths: x-ms-docs-key-type: Person responses: '200': - description: Success - content: - application/json: - schema: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' - - type: object - nullable: true + $ref: '#/components/responses/GetFavoriteAirlineResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -18615,20 +18474,7 @@ paths: type: string responses: '200': - description: Success - content: - application/json: - schema: - title: Collection of Trip - type: object - properties: - value: - type: array - items: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' - - type: object - nullable: true + $ref: '#/components/responses/GetFriendsTripsResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -18654,36 +18500,10 @@ paths: type: string x-ms-docs-key-type: Person requestBody: - description: Action parameters - content: - application/json: - schema: - type: object - properties: - userName: - type: string - tripId: - maximum: 2147483647 - minimum: -2147483648 - type: integer - format: int32 - required: true + $ref: '#/components/requestBodies/GetPeersForTripRequestBody' responses: '200': - description: Success - content: - application/json: - schema: - title: Collection of Person - type: object - properties: - value: - type: array - items: - anyOf: - - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' - - type: object - nullable: true + $ref: '#/components/responses/GetPeersForTripResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -19468,20 +19288,7 @@ paths: type: string x-ms-docs-key-type: Person requestBody: - description: Action parameters - content: - application/json: - schema: - type: object - properties: - userName: - type: string - tripId: - maximum: 2147483647 - minimum: -2147483648 - type: integer - format: int32 - required: true + $ref: '#/components/requestBodies/ShareTripRequestBody' responses: '204': description: Success @@ -19517,15 +19324,7 @@ paths: type: string responses: '200': - description: Success - content: - application/json: - schema: - type: object - properties: - value: - type: boolean - default: false + $ref: '#/components/responses/UpdatePersonLastNameResponse' default: $ref: '#/components/responses/error' deprecated: true @@ -21199,6 +20998,55 @@ components: application/json: schema: $ref: '#/components/schemas/StringCollectionResponse' + GetFavoriteAirlineResponse: + description: Success + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airline' + - type: object + nullable: true + GetFriendsTripsResponse: + description: Success + content: + application/json: + schema: + title: Collection of Trip + type: object + properties: + value: + type: array + items: + anyOf: + - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip' + - type: object + nullable: true + UpdatePersonLastNameResponse: + description: Success + content: + application/json: + schema: + type: object + properties: + value: + type: boolean + default: false + GetPeersForTripResponse: + description: Success + content: + application/json: + schema: + title: Collection of Person + type: object + properties: + value: + type: array + items: + anyOf: + - $ref: '#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person' + - type: object + nullable: true parameters: top: name: $top @@ -21356,6 +21204,36 @@ components: schema: $ref: '#/components/schemas/ReferenceUpdate' required: true + ShareTripRequestBody: + description: Action parameters + content: + application/json: + schema: + type: object + properties: + userName: + type: string + tripId: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + required: true + GetPeersForTripRequestBody: + description: Action parameters + content: + application/json: + schema: + type: object + properties: + userName: + type: string + tripId: + maximum: 2147483647 + minimum: -2147483648 + type: integer + format: int32 + required: true tags: - name: Airlines.Airline x-ms-docs-toc-type: page From d0a593072f0a316fd13392fa4fe3b84b77788062 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Mon, 5 Sep 2022 15:02:44 +0300 Subject: [PATCH 4/7] Update release notes --- .../Microsoft.OpenAPI.OData.Reader.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj index 538ad8a8..33b593b5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -15,13 +15,14 @@ netstandard2.0 Microsoft.OpenApi.OData true - 1.1.0-preview14 + 1.1.0-preview1 This package contains the codes you need to convert OData CSDL to Open API Document of Model. © Microsoft Corporation. All rights reserved. Microsoft OpenApi OData EDM https://github.com/Microsoft/OpenAPI.NET.OData - Fixes response schemas of actions and functions that return a collection to contain the nextLink property #231 +- Fixes duplicated actions/functions request body/response schemas #241 Microsoft.OpenApi.OData.Reader ..\..\tool\Microsoft.OpenApi.OData.snk From 3db7709471378fbae554e7a10d4115579dc2a8c2 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Tue, 6 Sep 2022 14:06:01 +0300 Subject: [PATCH 5/7] Formatting fixes --- .../Generator/OpenApiResponseGenerator.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index 71e6b901..ea47211d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -197,11 +197,11 @@ public static OpenApiResponse CreateOperationResponse(this ODataContext context, ? null : $"Collection of {entityType.Name}", Type = "object", Properties = new Dictionary + { { - { - "value", context.CreateEdmTypeSchema(operation.ReturnType) - } + "value", context.CreateEdmTypeSchema(operation.ReturnType) } + } }; } else if (operation.ReturnType.IsPrimitive()) @@ -212,11 +212,11 @@ public static OpenApiResponse CreateOperationResponse(this ODataContext context, { Type = "object", Properties = new Dictionary + { { - { - "value", context.CreateEdmTypeSchema(operation.ReturnType) - } + "value", context.CreateEdmTypeSchema(operation.ReturnType) } + } }; } else @@ -235,15 +235,15 @@ public static OpenApiResponse CreateOperationResponse(this ODataContext context, { Description = "Success", Content = new Dictionary + { { + mediaType, + new OpenApiMediaType { - mediaType, - new OpenApiMediaType - { - Schema = schema - } + Schema = schema } } + } }; return response; From f0f480f52554468f7fde058ff2814359f45a7e23 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Tue, 6 Sep 2022 14:17:49 +0300 Subject: [PATCH 6/7] Update XML comment of method --- .../Edm/EdmModelExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index e28acdc1..e88fecb1 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -200,11 +200,11 @@ public static bool IsOperationOverload(this IEdmModel model, IEdmOperation opera } /// - /// Checks whether operation targets singleton and entityset of the same type. + /// Checks whether operation targets singletons and/or entitysets of the same type. /// /// The Edm model. - /// - /// The test operations. + /// The test operations. + /// True/false. public static bool OperationTargetsMultiplePaths(this IEdmModel model, IEdmOperation operation) { Utils.CheckArgumentNull(model, nameof(model)); From 93e4de0f1837a9e94cd421830af9c228dc03a55d Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Tue, 6 Sep 2022 21:26:22 +0300 Subject: [PATCH 7/7] Use pattern matching in if statement --- .../Operation/EdmActionOperationHandler.cs | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs index 4e1da45d..a3734485 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs @@ -37,28 +37,24 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - if (EdmOperation is IEdmAction action) - { - OpenApiRequestBody requestBody = Context.CreateRequestBody(action); - if (requestBody != null) + if (EdmOperation is IEdmAction action && Context.CreateRequestBody(action) is OpenApiRequestBody requestBody) + { + if (Context.Model.OperationTargetsMultiplePaths(action)) { - if (Context.Model.OperationTargetsMultiplePaths(action)) + operation.RequestBody = new OpenApiRequestBody { - operation.RequestBody = new OpenApiRequestBody + UnresolvedReference = true, + Reference = new OpenApiReference { - UnresolvedReference = true, - Reference = new OpenApiReference - { - Type = ReferenceType.RequestBody, - Id = $"{action.Name}RequestBody" - } - }; - } - else - { - operation.RequestBody = requestBody; - } + Type = ReferenceType.RequestBody, + Id = $"{action.Name}RequestBody" + } + }; } + else + { + operation.RequestBody = requestBody; + } } base.SetRequestBody(operation);