Fixes response objects for operations that return single primitive type values (#127)
* Refactor similar code into one function; add fix for responses for primitive types * Add new param to method and add tests for this * Update test files * Address PR review suggestion
This commit is contained in:
parent
03b6000a84
commit
226ce62303
|
@ -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
|
|||
/// </summary>
|
||||
/// <param name="context">The OData context.</param>
|
||||
/// <param name="operationImport">The Edm operation import.</param>
|
||||
/// <param name="path">The OData path.</param>
|
||||
/// <returns>The created <see cref="OpenApiResponses"/>.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -86,13 +89,15 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
/// </summary>
|
||||
/// <param name="context">The OData context.</param>
|
||||
/// <param name="operation">The Edm operation.</param>
|
||||
/// <param name="path">The OData path.</param>
|
||||
/// <returns>The created <see cref="OpenApiResponses"/>.</returns>
|
||||
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<string, OpenApiSchema>
|
||||
{
|
||||
{
|
||||
"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<string, OpenApiSchema>
|
||||
{
|
||||
{
|
||||
"value", context.CreateEdmTypeSchema(operation.ReturnType)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
schema = context.CreateEdmTypeSchema(operation.ReturnType);
|
||||
}
|
||||
|
||||
OpenApiResponse response = new()
|
||||
{
|
||||
Description = "Success",
|
||||
Content = new Dictionary<string, OpenApiMediaType>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -166,56 +166,7 @@ namespace Microsoft.OpenApi.OData.Operation
|
|||
/// <inheritdoc/>
|
||||
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<string, OpenApiSchema>
|
||||
{
|
||||
{
|
||||
"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<string, OpenApiMediaType>
|
||||
{
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
|
|||
ODataContext context = null;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("context", () => context.CreateResponses(operationImport: null));
|
||||
Assert.Throws<ArgumentNullException>("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<ArgumentNullException>("operationImport", () => context.CreateResponses(operationImport: null));
|
||||
Assert.Throws<ArgumentNullException>("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<ArgumentNullException>("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<ArgumentNullException>("context", () => context.CreateResponses(operation: null));
|
||||
Assert.Throws<ArgumentNullException>("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<ArgumentNullException>("operation", () => context.CreateResponses(operation: null));
|
||||
Assert.Throws<ArgumentNullException>("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<ArgumentNullException>("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<IEdmOperation>().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<IEdmOperation>().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
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue