Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes empty response objects for OData type cast paths #547

Merged
merged 7 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,69 +143,15 @@ protected override void SetExtensions(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
if(ComplexPropertySegment.Property.Type.IsCollection())
SetCollectionResponse(operation);
if (ComplexPropertySegment.Property.Type.IsCollection())
SetCollectionResponse(operation, ComplexPropertySegment.ComplexType.FullName());
else
SetSingleResponse(operation);
operation.AddErrorResponses(Context.Settings, false);
SetSingleResponse(operation, ComplexPropertySegment.ComplexType.FullName());

operation.AddErrorResponses(Context.Settings, false);
base.SetResponses(operation);
}
private void SetCollectionResponse(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
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)
{
schema = new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.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
}
}
},
}
}
};
}

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,79 +195,17 @@ protected override void SetBasicInfo(OpenApiOperation operation)

/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
if (IsSingleElement)
SetSingleResponse(operation);
{
if (IsSingleElement)
SetSingleResponse(operation, TargetSchemaElement.FullName());
else
SetCollectionResponse(operation);
SetCollectionResponse(operation, TargetSchemaElement.FullName());

operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}

private void SetCollectionResponse(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
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;

if (Context.Settings.EnableDerivedTypesReferencesForResponses)
{
schema = EdmModelHelper.GetDerivedTypesReferenceSchema(targetStructuredType, Context.Model);
}
andrueastman marked this conversation as resolved.
Show resolved Hide resolved

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
}
}
},
}
}
};
}

/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
Expand Down
60 changes: 58 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,63 @@ 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, string targetElementFullName)
{
Utils.CheckArgumentNull(operation, nameof(operation));
Utils.CheckArgumentNullOrEmpty(targetElementFullName, nameof(targetElementFullName));

var schema = new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = targetElementFullName
}
};

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
Loading