diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs
index c838a67..01c8043 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs
@@ -4,6 +4,7 @@
// ------------------------------------------------------------
using System.Collections.Generic;
+using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
@@ -72,13 +73,15 @@ namespace Microsoft.OpenApi.OData.Generator
///
/// The OData context.
/// The Edm operation import.
+ /// The OData path.
/// The created .
- public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport)
+ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport, ODataPath path)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operationImport, nameof(operationImport));
+ Utils.CheckArgumentNull(path, nameof(path));
- return context.CreateResponses(operationImport.Operation);
+ return context.CreateResponses(operationImport.Operation, path);
}
///
@@ -86,13 +89,15 @@ namespace Microsoft.OpenApi.OData.Generator
///
/// The OData context.
/// The Edm operation.
+ /// The OData path.
/// The created .
- public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation)
+ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation, ODataPath path)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operation, nameof(operation));
+ Utils.CheckArgumentNull(path, nameof(path));
- OpenApiResponses responses = new OpenApiResponses();
+ OpenApiResponses responses = new();
if (operation.IsAction() && operation.ReturnType == null)
{
@@ -100,7 +105,44 @@ namespace Microsoft.OpenApi.OData.Generator
}
else
{
- OpenApiResponse response = new OpenApiResponse
+ OpenApiSchema schema;
+ if (operation.ReturnType.IsCollection())
+ {
+ // 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
+ {
+ {
+ "value", context.CreateEdmTypeSchema(operation.ReturnType)
+ }
+ }
+ };
+ }
+ 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
+ {
+ Type = "object",
+ Properties = new Dictionary
+ {
+ {
+ "value", context.CreateEdmTypeSchema(operation.ReturnType)
+ }
+ }
+ };
+ }
+ else
+ {
+ schema = context.CreateEdmTypeSchema(operation.ReturnType);
+ }
+
+ OpenApiResponse response = new()
{
Description = "Success",
Content = new Dictionary
@@ -109,7 +151,7 @@ namespace Microsoft.OpenApi.OData.Generator
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
- Schema = context.CreateEdmTypeSchema(operation.ReturnType)
+ Schema = schema
}
}
}
@@ -117,7 +159,7 @@ namespace Microsoft.OpenApi.OData.Generator
responses.Add(Constants.StatusCode200, response);
}
- // both action & function has the default response.
+ // Both action & function have the default response.
responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
return responses;
diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs
index c26317f..8125f8a 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs
@@ -79,7 +79,7 @@ namespace Microsoft.OpenApi.OData.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);
+ operation.Responses = Context.CreateResponses(EdmOperationImport, Path);
base.SetResponses(operation);
}
diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs
index 1e98109..4b2c64d 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs
@@ -166,56 +166,7 @@ namespace Microsoft.OpenApi.OData.Operation
///
protected override void SetResponses(OpenApiOperation operation)
{
- if (EdmOperation.IsAction() && EdmOperation.ReturnType == null)
- {
- operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
- }
- else
- {
- OpenApiSchema schema;
- if (EdmOperation.ReturnType.TypeKind() == EdmTypeKind.Collection)
- {
- // Get the entity type of the previous segment
- IEdmEntityType entityType = Path.Segments.Reverse().Skip(1).Take(1).FirstOrDefault().EntityType;
- schema = new OpenApiSchema
- {
- Title = $"Collection of {entityType.Name}",
- Type = "object",
- Properties = new Dictionary
- {
- {
- "value", Context.CreateEdmTypeSchema(EdmOperation.ReturnType)
- }
- }
- };
- }
- else
- {
- schema = Context.CreateEdmTypeSchema(EdmOperation.ReturnType);
- }
-
- // function should have a return type.
- OpenApiResponse response = new OpenApiResponse
- {
- Description = "Success",
- Content = new Dictionary
- {
- {
- Constants.ApplicationJsonMediaType,
- new OpenApiMediaType
- {
- Schema = schema
- }
- }
- }
- };
-
- operation.Responses.Add(Constants.StatusCode200, response);
- }
-
- // both action & function has the default response.
- operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
-
+ operation.Responses = Context.CreateResponses(EdmOperation, Path);
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 c1ed87e..40f33dc 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiResponseGeneratorTests.cs
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiResponseGeneratorTests.cs
@@ -104,7 +104,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = null;
// Act & Assert
- Assert.Throws("context", () => context.CreateResponses(operationImport: null));
+ Assert.Throws("context", () => context.CreateResponses(operationImport: null, path: null));
}
[Fact]
@@ -114,7 +114,19 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = new ODataContext(EdmCoreModel.Instance);
// Act & Assert
- Assert.Throws("operationImport", () => context.CreateResponses(operationImport: null));
+ 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));
}
[Fact]
@@ -124,7 +136,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = null;
// Act & Assert
- Assert.Throws("context", () => context.CreateResponses(operation: null));
+ Assert.Throws("context", () => context.CreateResponses(operation: null, path: null));
}
[Fact]
@@ -134,7 +146,19 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
ODataContext context = new ODataContext(EdmCoreModel.Instance);
// Act & Assert
- Assert.Throws("operation", () => context.CreateResponses(operation: null));
+ 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));
}
[Theory]
@@ -157,13 +181,15 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
{
IEdmOperationImport operationImport = model.EntityContainer.OperationImports().First(o => o.Name == operationName);
Assert.NotNull(operationImport); // guard
- responses = context.CreateResponses(operationImport);
+ ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport));
+ responses = context.CreateResponses(operationImport, path);
}
else
{
IEdmOperation operation = model.SchemaElements.OfType().First(o => o.Name == operationName);
Assert.NotNull(operation); // guard
- responses = context.CreateResponses(operation);
+ ODataPath path = new ODataPath(new ODataOperationSegment(operation));
+ responses = context.CreateResponses(operation, path);
}
// Assert
@@ -195,7 +221,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
Assert.NotNull(mediaType.Schema.AnyOf);
var anyOf = Assert.Single(mediaType.Schema.AnyOf);
Assert.Equal("Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person", anyOf.Reference.Id);
- }
+ }
}
[Theory]
@@ -214,13 +240,15 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
{
IEdmOperationImport operationImport = model.EntityContainer.OperationImports().First(o => o.Name == actionName);
Assert.NotNull(operationImport); // guard
- responses = context.CreateResponses(operationImport);
+ ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport));
+ responses = context.CreateResponses(operationImport, path);
}
else
{
IEdmOperation operation = model.SchemaElements.OfType().First(o => o.Name == actionName);
Assert.NotNull(operation); // guard
- responses = context.CreateResponses(operation);
+ ODataPath path = new ODataPath(new ODataOperationSegment(operation));
+ responses = context.CreateResponses(operation, path);
}
// Assert
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 8ad1c25..7949025 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
@@ -1313,8 +1313,13 @@
"200": {
"description": "Success",
"schema": {
- "default": false,
- "type": "boolean"
+ "type": "object",
+ "properties": {
+ "value": {
+ "default": false,
+ "type": "boolean"
+ }
+ }
}
},
"default": {
@@ -3000,8 +3005,13 @@
"200": {
"description": "Success",
"schema": {
- "default": false,
- "type": "boolean"
+ "type": "object",
+ "properties": {
+ "value": {
+ "default": false,
+ "type": "boolean"
+ }
+ }
}
},
"default": {
@@ -4767,8 +4777,13 @@
"200": {
"description": "Success",
"schema": {
- "default": false,
- "type": "boolean"
+ "type": "object",
+ "properties": {
+ "value": {
+ "default": false,
+ "type": "boolean"
+ }
+ }
}
},
"default": {
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 dbe4998..5a5533a 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
@@ -898,8 +898,11 @@ paths:
'200':
description: Success
schema:
- default: false
- type: boolean
+ type: object
+ properties:
+ value:
+ default: false
+ type: boolean
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@@ -2079,8 +2082,11 @@ paths:
'200':
description: Success
schema:
- default: false
- type: boolean
+ type: object
+ properties:
+ value:
+ default: false
+ type: boolean
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
@@ -3320,8 +3326,11 @@ paths:
'200':
description: Success
schema:
- default: false
- type: boolean
+ type: object
+ properties:
+ value:
+ default: false
+ type: boolean
default:
$ref: '#/responses/error'
x-ms-docs-operation-type: function
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 5d09291..4c06fd0 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json
@@ -1483,8 +1483,13 @@
"content": {
"application/json": {
"schema": {
- "type": "boolean",
- "default": false
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "boolean",
+ "default": false
+ }
+ }
}
}
}
@@ -3366,8 +3371,13 @@
"content": {
"application/json": {
"schema": {
- "type": "boolean",
- "default": false
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "boolean",
+ "default": false
+ }
+ }
}
}
}
@@ -5351,8 +5361,13 @@
"content": {
"application/json": {
"schema": {
- "type": "boolean",
- "default": false
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "boolean",
+ "default": false
+ }
+ }
}
}
}
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 5c441d1..7b9f87f 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml
@@ -992,8 +992,11 @@ paths:
content:
application/json:
schema:
- type: boolean
- default: false
+ type: object
+ properties:
+ value:
+ type: boolean
+ default: false
default:
$ref: '#/components/responses/error'
x-ms-docs-operation-type: function
@@ -2285,8 +2288,11 @@ paths:
content:
application/json:
schema:
- type: boolean
- default: false
+ type: object
+ properties:
+ value:
+ type: boolean
+ default: false
default:
$ref: '#/components/responses/error'
x-ms-docs-operation-type: function
@@ -3649,8 +3655,11 @@ paths:
content:
application/json:
schema:
- type: boolean
- default: false
+ type: object
+ properties:
+ value:
+ type: boolean
+ default: false
default:
$ref: '#/components/responses/error'
x-ms-docs-operation-type: function