Skip to content

Resolves operationId and tag names for OData cast paths #338

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

Merged
merged 25 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3fd4939
Initial commit to update descriptions and tags
irvinesunday Jan 31, 2023
40762cb
Second init for operations and tags
irvinesunday Jan 31, 2023
1bcc59b
Get operation ids
irvinesunday Jan 31, 2023
57fbd6a
Refactor out common code into a helper class for re-use
irvinesunday Feb 1, 2023
f7930ef
Fix tags; refactor; remove redundant code
irvinesunday Feb 1, 2023
7b4efdb
Updates release notes
irvinesunday Feb 1, 2023
b379821
Add SetTags operation for $count operations; update operationId
irvinesunday Mar 8, 2023
993a03e
Remove unnecessary usings
irvinesunday Mar 8, 2023
4eed44a
Add operation id for $count paths for OData type cast segments
irvinesunday Mar 8, 2023
8cc0aaa
Refactor variable name
irvinesunday Mar 8, 2023
aade254
Merge remote-tracking branch 'origin/master' into fix/is/odata-type-c…
irvinesunday Mar 8, 2023
f85e816
Bump up lib. version
irvinesunday Mar 9, 2023
10a9c62
Refactor out private method; update tag generation
irvinesunday Mar 9, 2023
8109875
Update tags generation
irvinesunday Mar 9, 2023
178191a
Create common reusable class
irvinesunday Mar 9, 2023
47ad99a
Generate complex property path tag name in a helper class
irvinesunday Mar 13, 2023
d4680b5
Generate tags for entity set $count paths
irvinesunday Mar 13, 2023
98612fd
Variables renaming
irvinesunday Mar 13, 2023
6ef2f4b
Update integration and unit tests
irvinesunday Mar 13, 2023
abb3c34
Refactor methods that generate operation ids and tags
irvinesunday Mar 14, 2023
ca1e12c
Fix formatting; use methods in helper class to generate tags
irvinesunday Mar 14, 2023
a8785e1
Update unit and integration tests
irvinesunday Mar 15, 2023
490cf70
Variable renaming; fix type cast and complex types operation ids
irvinesunday Mar 15, 2023
d79cdfd
Merge branch 'master' into fix/is/odata-type-cast-opIds
irvinesunday Mar 28, 2023
0c847cf
Bump up version
irvinesunday Mar 28, 2023
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
97 changes: 91 additions & 6 deletions src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

namespace Microsoft.OpenApi.OData.Common
Expand All @@ -22,7 +23,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType
{
Utils.CheckArgumentNull(structuredType, nameof(structuredType));
Utils.CheckArgumentNull(edmModel, nameof(edmModel));
if(structuredType is not IEdmSchemaElement schemaElement) throw new ArgumentException("The type is not a schema element.", nameof(structuredType));
if (structuredType is not IEdmSchemaElement schemaElement) throw new ArgumentException("The type is not a schema element.", nameof(structuredType));

IEnumerable<IEdmSchemaElement> derivedTypes = edmModel.FindAllDerivedTypes(structuredType).OfType<IEdmSchemaElement>();

Expand All @@ -32,12 +33,12 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType
}

OpenApiSchema schema = new()
{
{
OneOf = new List<OpenApiSchema>()
};

OpenApiSchema baseTypeSchema = new()
{
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Expand All @@ -50,7 +51,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType
foreach (IEdmSchemaElement derivedType in derivedTypes)
{
OpenApiSchema derivedTypeSchema = new()
{
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Expand All @@ -62,7 +63,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType
};

return schema;
}
}

/// <summary>
/// Verifies whether the provided navigation restrictions allow for navigability of a navigation property.
Expand All @@ -83,7 +84,91 @@ internal static bool NavigationRestrictionsAllowsNavigability(
// if the individual has no navigability setting, use the global navigability setting
// Default navigability for all navigation properties of the annotation target.
// Individual navigation properties can override this value via `RestrictedProperties/Navigability`.
return restrictionProperty?.Navigability != null || restrictionType == null || restrictionType.IsNavigable;
return restrictionProperty?.Navigability != null || restrictionType == null || restrictionType.IsNavigable;
}

/// <summary>
/// Generates the operation id for a navigation property path.
/// </summary>
/// <param name="path">The target <see cref="ODataPath"/>.</param>
/// <param name="navigationSource">The <see cref="IEdmNavigationSource"/> of the target path.</param>
/// <param name="prefix">Identifier indicating whether it is a collection-valued non-indexed navigation property.</param>
/// <returns>The operation id name.</returns>
internal static string GenerateNavigationPropertyPathOperationId(ODataPath path, IEdmNavigationSource navigationSource, string prefix = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we standardize the naming convention of operationIds to what we have in DevX API - https://github.com/microsoftgraph/microsoft-graph-devx-api/blob/dev/OpenAPIService/PowershellFormatter.cs?
For example:

  • Remove hash suffix values from operationIds of function paths.
  • Add '_' to separate verb (action) in an operationId. This typically the last . or second . for OData cast paths.
  • PUT operations should have Set as the verb in an operationId {xxx}_Set{yyy}.

In PowerShell, we use operationIds to form command names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comments at #324 (comment) on operationIds and tags for count and complex property paths.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we standardize the naming convention of operationIds to what we have in DevX API - https://github.com/microsoftgraph/microsoft-graph-devx-api/blob/dev/OpenAPIService/PowershellFormatter.cs? For example:

  • Remove hash suffix values from operationIds of function paths.
  • Add '_' to separate verb (action) in an operationId. This typically the last . or second . for OData cast paths.
  • PUT operations should have Set as the verb in an operationId {xxx}_Set{yyy}.

In PowerShell, we use operationIds to form command names.

There are other clients who rely on the operation ids, not sure it will be a good idea to handle that in this library. See this issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are also using AutoREST in the referenced issue - microsoftgraph/msgraph-metadata#289. Standardizing the operationIds here and ensuring uniqueness will have the net effect of fixing their issue.

To unblock this change, I've created an issue at #361 for us to discuss this further.

{
if (path == null || navigationSource == null)
return null;

IList<string> items = new List<string>
{
navigationSource.Name
};

var lastpath = path.Segments.Last(c => c is ODataNavigationPropertySegment);
foreach (var segment in path.Segments.Skip(1).OfType<ODataNavigationPropertySegment>())
{
if (segment == lastpath)
{
if (prefix != null)
{
items.Add(prefix + Utils.UpperFirstChar(segment.NavigationProperty.Name));
}
else
{
items.Add(Utils.UpperFirstChar(segment.NavigationProperty.Name));
}

break;
}
else
{
items.Add(segment.NavigationProperty.Name);
}
}

return string.Join(".", items);
}

/// <summary>
/// Generates the tag for a navigation property path.
/// </summary>
/// <param name="path">The target <see cref="ODataPath"/>.</param>
/// <param name="navigationSource">The <see cref="IEdmNavigationSource"/> of the target path.</param>
/// <param name="navigationProperty">The target <see cref="IEdmNavigationProperty"/>.</param>
/// <param name="context">The <see cref="ODataContext"/>.</param>
/// <returns>The tag name.</returns>
internal static string GenerateNavigationPropertyPathTag(ODataPath path, IEdmNavigationSource navigationSource, IEdmNavigationProperty navigationProperty, ODataContext context)
{
if (path == null || navigationSource == null || navigationProperty == null)
return null;

IList<string> items = new List<string>
{
navigationSource.Name
};

foreach (var segment in path.Segments.Skip(1).OfType<ODataNavigationPropertySegment>())
{
if (segment.NavigationProperty == navigationProperty)
{
items.Add(navigationProperty.ToEntityType().Name);
break;
}
else
{
if (items.Count >= context.Settings.TagDepth - 1)
{
items.Add(segment.NavigationProperty.ToEntityType().Name);
break;
}
else
{
items.Add(segment.NavigationProperty.Name);
}
}
}

return string.Join(".", items);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,13 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<PackageId>Microsoft.OpenApi.OData</PackageId>
<SignAssembly>true</SignAssembly>
<Version>1.2.0</Version>
<Version>1.3.0</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>
- Use convert setting to toggle between referencing @odata.count and @odata.nextLink #282
- Fixes URL Path parameters of type datetime generated as strings with quotes #262
- Set assembly version used for conversion in OpenApiInfo object #208
- Adds create and update operations to non-containment navigation properties when restrictions annotations are explicitly set to true #265
- Generate odata.nextLink and odata.deltaLink properties on delta functions response schemas #285
- Omits paths with PathItems without any operation #148
- Expands navigation properties of derived types only if declaring navigation property is a containment #269
- Adds custom parameters to $count and ODataTypeCast paths' Get operations #207
- Adds support for configuring the default value of derived types' @odata.type property #304
- Adds OData query parameters to $count endpoints #313
- Finds all the derived types for a schema element #84
- Add support for paths with alternate keys #120, #329
- Resolves operationId and tag names for OData cast paths #324
</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 @@ -78,33 +78,7 @@ protected override void Initialize(ODataContext context, ODataPath path)
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
IList<string> items = new List<string>
{
NavigationSource.Name
};

foreach (var segment in Path.Segments.Skip(1).OfType<ODataNavigationPropertySegment>())
{
if (segment.NavigationProperty == NavigationProperty)
{
items.Add(NavigationProperty.ToEntityType().Name);
break;
}
else
{
if (items.Count >= Context.Settings.TagDepth - 1)
{
items.Add(segment.NavigationProperty.ToEntityType().Name);
break;
}
else
{
items.Add(segment.NavigationProperty.Name);
}
}
}

string name = string.Join(".", items);
string name = EdmModelHelper.GenerateNavigationPropertyPathTag(Path, NavigationSource, NavigationProperty, Context);
OpenApiTag tag = new()
{
Name = name
Expand All @@ -125,37 +99,10 @@ protected override void SetExtensions(OpenApiOperation operation)
base.SetExtensions(operation);
}

protected string GetOperationId(string prefix = null)
{
IList<string> items = new List<string>
{
NavigationSource.Name
};

var lastpath = Path.Segments.Last(c => c is ODataNavigationPropertySegment);
foreach (var segment in Path.Segments.Skip(1).OfType<ODataNavigationPropertySegment>())
{
if (segment == lastpath)
{
if (prefix != null)
{
items.Add(prefix + Utils.UpperFirstChar(segment.NavigationProperty.Name));
}
else
{
items.Add(Utils.UpperFirstChar(segment.NavigationProperty.Name));
}

break;
}
else
{
items.Add(segment.NavigationProperty.Name);
}
}

return string.Join(".", items);
}
internal string GetOperationId(string prefix = null)
{
return EdmModelHelper.GenerateNavigationPropertyPathOperationId(Path, NavigationSource, prefix);
}

/// <inheritdoc/>
protected override void SetExternalDocs(OpenApiOperation operation)
Expand Down
Loading