Skip to content

Commit

Permalink
Fixes empty response objects for OData type cast paths (#547)
Browse files Browse the repository at this point in the history
* Refactor response method; update conditionality

* Revert creating response content of collections

This will been created in the response section

* Update integration tests

* Update release notes

* Remove unnecessary whitespace

* Update release note text

* PR review fix

Check for: Context.Settings.EnableDerivedTypesReferencesForResponses
  • Loading branch information
irvinesunday authored Jun 26, 2024
1 parent fb8f8f8 commit fd29980
Show file tree
Hide file tree
Showing 8 changed files with 1,810 additions and 742 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<PackageId>Microsoft.OpenApi.OData</PackageId>
<SignAssembly>true</SignAssembly>
<Version>1.6.6</Version>
<Version>1.6.7</Version>
<Description>This package contains the codes you need to convert OData CSDL to Open API Document of Model.</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageTags>Microsoft OpenApi OData EDM</PackageTags>
<RepositoryUrl>https://github.com/Microsoft/OpenAPI.NET.OData</RepositoryUrl>
<PackageReleaseNotes>
- Adds support for IndexableByKey restrictions annotations on entity sets #541
- Fixes empty response objects for OData type cast paths. #546
</PackageReleaseNotes>
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
<AssemblyOriginatorKeyFile>..\..\tool\Microsoft.OpenApi.OData.snk</AssemblyOriginatorKeyFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,39 +143,13 @@ protected override void SetExtensions(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
if(ComplexPropertySegment.Property.Type.IsCollection())
SetCollectionResponse(operation);
else
SetSingleResponse(operation);
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
private void SetCollectionResponse(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
if (ComplexPropertySegment.Property.Type.IsCollection())
{
{
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
UnresolvedReference = true,
Reference = new OpenApiReference()
{
Type = ReferenceType.Response,
Id = $"{ComplexPropertySegment.ComplexType.FullName()}{Constants.CollectionSchemaSuffix}"
},
}
}
};
}
private void SetSingleResponse(OpenApiOperation operation)
{
OpenApiSchema schema = null;

if (schema == null)
SetCollectionResponse(operation, ComplexPropertySegment.ComplexType.FullName());
}
else
{
schema = new OpenApiSchema
OpenApiSchema schema = new()
{
UnresolvedReference = true,
Reference = new OpenApiReference
Expand All @@ -184,28 +158,14 @@ private void SetSingleResponse(OpenApiOperation operation)
Id = ComplexPropertySegment.ComplexType.FullName()
}
};

SetSingleResponse(operation, schema);
}
operation.Responses = new OpenApiResponses
{
{
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
Description = "Result entities",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = schema
}
}
},
}
}
};

operation.AddErrorResponses(Context.Settings, false);
base.SetResponses(operation);
}

protected override void SetSecurity(OpenApiOperation operation)
{
if (_readRestrictions?.Permissions == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler

private bool isKeySegment;

private bool secondLastSegmentIsComplexProperty;

private bool IsSingleElement
{
get => isKeySegment ||
singleton != null ||
secondLastSegmentIsComplexProperty ||
singleton != null ||
(navigationProperty != null &&
!navigationProperty.Type.IsCollection() &&
entitySet == null);
Expand All @@ -62,7 +65,8 @@ protected override void Initialize(ODataContext context, ODataPath path)
// reseting the fields as we're reusing the handler
singleton = null;
isKeySegment = false;
restriction = null;
secondLastSegmentIsComplexProperty = false;
restriction = null;
entitySet = null;
navigationProperty = null;
parentStructuredType = null;
Expand Down Expand Up @@ -102,6 +106,10 @@ protected override void Initialize(ODataContext context, ODataPath path)
SetAnnotatableRestrictionFromNavigationSourceSegment(sourceSegment1);
}
}
else if (SecondLastSegment is ODataComplexPropertySegment)
{
secondLastSegmentIsComplexProperty = true;
}

if (path.Last() is ODataTypeCastSegment odataTypeCastSegment)
{
Expand Down Expand Up @@ -187,77 +195,39 @@ protected override void SetBasicInfo(OpenApiOperation operation)

/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
if (IsSingleElement)
SetSingleResponse(operation);
else
SetCollectionResponse(operation);
{
if (IsSingleElement)
{
OpenApiSchema schema = null;

operation.AddErrorResponses(Context.Settings, false);
if (Context.Settings.EnableDerivedTypesReferencesForResponses)
{
schema = EdmModelHelper.GetDerivedTypesReferenceSchema(targetStructuredType, Context.Model);
}

base.SetResponses(operation);
}
if (schema == null)
{
schema = new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = TargetSchemaElement.FullName()
}
};
}

private void SetCollectionResponse(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
SetSingleResponse(operation, schema);
}
else
{
{
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
UnresolvedReference = true,
Reference = new OpenApiReference()
{
Type = ReferenceType.Response,
Id = $"{TargetSchemaElement.FullName()}{Constants.CollectionSchemaSuffix}"
},
}
}
};
}

private void SetSingleResponse(OpenApiOperation operation)
{
OpenApiSchema schema = null;
SetCollectionResponse(operation, TargetSchemaElement.FullName());
}

if (Context.Settings.EnableDerivedTypesReferencesForResponses)
{
schema = EdmModelHelper.GetDerivedTypesReferenceSchema(targetStructuredType, Context.Model);
}
operation.AddErrorResponses(Context.Settings, false);

if (schema == null)
{
schema = new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = TargetSchemaElement.FullName()
}
};
}
operation.Responses = new OpenApiResponses
{
{
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
Description = "Result entities",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = schema
}
}
},
}
}
};
base.SetResponses(operation);
}

/// <inheritdoc/>
Expand Down
50 changes: 48 additions & 2 deletions src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using System.Text;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.MicrosoftExtensions;
using Microsoft.OpenApi.Models;
Expand Down Expand Up @@ -298,5 +296,53 @@ protected virtual void SetCustomLinkRelType()
}
}

internal void SetCollectionResponse(OpenApiOperation operation, string targetElementFullName)
{
Utils.CheckArgumentNull(operation, nameof(operation));
Utils.CheckArgumentNullOrEmpty(targetElementFullName, nameof(targetElementFullName));

operation.Responses = new OpenApiResponses
{
{
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
UnresolvedReference = true,
Reference = new OpenApiReference()
{
Type = ReferenceType.Response,
Id = $"{targetElementFullName}{Constants.CollectionSchemaSuffix}"
}
}
}
};
}

internal void SetSingleResponse(OpenApiOperation operation, OpenApiSchema schema)
{
Utils.CheckArgumentNull(operation, nameof(operation));
Utils.CheckArgumentNull(schema, nameof(schema));

operation.Responses = new OpenApiResponses
{
{
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
Description = "Entity result.",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = schema
}
}
},
}
}
};
}
}
}
Loading

0 comments on commit fd29980

Please sign in to comment.