Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
78f8201
Add configuration for showing links to external documentation for ope…
millicentachieng Jul 29, 2022
305b2de
Add Links to Core vocabularies
millicentachieng Jul 30, 2022
aa79409
Add Core vocabulary constants
millicentachieng Jul 30, 2022
a3685f0
Add SetExternalDocs method to OperationHandler
millicentachieng Jul 31, 2022
7b0856a
Add ExternalDocs object to entity set path items
millicentachieng Jul 31, 2022
9735886
Add ExternalDocs object to action and function path items
millicentachieng Jul 31, 2022
0d9a8f8
Update LinksType vocabulary
millicentachieng Jul 31, 2022
0dd2223
Add ExternalDocs object to singleton path items
millicentachieng Jul 31, 2022
7f77fa6
Add description from CSDL for action and function operations
millicentachieng Jul 31, 2022
c105ea0
Move SetExternalDocs to base class
millicentachieng Aug 1, 2022
d247415
Add ExternalDocs object to navigation property path items
millicentachieng Aug 1, 2022
bb3a5ec
Rename vocabulary from LinksType to Link to match name of complex type
millicentachieng Aug 2, 2022
7d61fcf
Add extension method for getting external docs
millicentachieng Aug 3, 2022
ee8a2c2
Add link rel values used in links vocabulary
millicentachieng Aug 3, 2022
26ec2f1
Select link to add to operation based on operation type and target type
millicentachieng Aug 16, 2022
f458088
Merge branch 'master' into ma/add-documentation-links-annotations
millicentachieng Aug 16, 2022
3f63686
Fix failing tests for media type annotations
millicentachieng Aug 16, 2022
9a07660
Address PR comments
millicentachieng Aug 19, 2022
583c382
Make link relation types used to extract external docs links from CSD…
millicentachieng Aug 23, 2022
60c4402
Use switch statement to get link relation type for operation
millicentachieng Aug 23, 2022
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
17 changes: 17 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Vocabulary;
using Microsoft.OpenApi.OData.Vocabulary.Authorization;
using Microsoft.OpenApi.OData.Vocabulary.Core;

namespace Microsoft.OpenApi.OData.Edm
{
Expand Down Expand Up @@ -256,6 +258,21 @@ public static IEnumerable<T> GetCollection<T>(this IEdmModel model, IEdmVocabula
});
}

/// <summary>
/// Gets the links record value (a complex type) for the given <see cref="IEdmVocabularyAnnotatable"/>.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm target.</param>
/// <param name="linkRel">The link relation type for path operation.</param>
/// <returns>Null or the links record value (a complex type) for this annotation.</returns>
public static Link GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string linkRel)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));

return model.GetCollection<Link>(target, CoreConstants.Links)?.FirstOrDefault(x => x.Rel == linkRel);
}

/// <summary>
/// Create the corresponding Authorization object.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ internal IEnumerable<DeprecatedRevisionsType> GetDeprecationInformations(IEdmVoc
{
return annotable == null ?
Enumerable.Empty<DeprecatedRevisionsType>() :
(Model?.GetCollection<DeprecatedRevisionsType>(annotable, "Org.OData.Core.V1.Revisions") ??
(Model?.GetCollection<DeprecatedRevisionsType>(annotable, CoreConstants.Revisions) ??
Enumerable.Empty<DeprecatedRevisionsType>());
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Extensions;
using Microsoft.OpenApi.OData.Vocabulary.Core;

namespace Microsoft.OpenApi.OData
{
Expand Down Expand Up @@ -179,6 +180,11 @@ public string PathPrefix
/// </summary>
public bool ShowMsDosGroupPath { get; set; } = true;

/// <summary>
/// Gets/sets links to external documentation for operations
/// </summary>
public bool ShowExternalDocs { get; set; } = true;

/// <summary>
/// Gets/sets a the path provider.
/// </summary>
Expand Down Expand Up @@ -259,6 +265,20 @@ public string PathPrefix
/// </summary>
public bool UseSuccessStatusCodeRange { get; set; } = false;

/// <summary>
/// Get/Sets a dictionary containing a mapping of HTTP methods to custom link relation types
/// </summary>
public Dictionary<LinkRelKey, string> CustomHttpMethodLinkRelMapping { get; set; } = new()
{
{ LinkRelKey.List, "https://graph.microsoft.com/rels/docs/list" },
{ LinkRelKey.ReadByKey, "https://graph.microsoft.com/rels/docs/get" },
{ LinkRelKey.Create, "https://graph.microsoft.com/rels/docs/create" },
{ LinkRelKey.Update, "https://graph.microsoft.com/rels/docs/update" },
{ LinkRelKey.Delete, "https://graph.microsoft.com/rels/docs/delete" },
{ LinkRelKey.Action, "https://graph.microsoft.com/rels/docs/action" },
{ LinkRelKey.Function, "https://graph.microsoft.com/rels/docs/function" }
};

internal OpenApiConvertSettings Clone()
{
var newSettings = new OpenApiConvertSettings
Expand Down Expand Up @@ -288,6 +308,7 @@ internal OpenApiConvertSettings Clone()
RequireDerivedTypesConstraintForBoundOperations = this.RequireDerivedTypesConstraintForBoundOperations,
ShowSchemaExamples = this.ShowSchemaExamples,
ShowRootPath = this.ShowRootPath,
ShowExternalDocs = this.ShowExternalDocs,
PathProvider = this.PathProvider,
EnableDollarCountPath = this.EnableDollarCountPath,
AddSingleQuotesForStringParameters = this.AddSingleQuotesForStringParameters,
Expand All @@ -300,6 +321,7 @@ internal OpenApiConvertSettings Clone()
RequireRestrictionAnnotationsToGenerateComplexPropertyPaths = this.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths,
ExpandDerivedTypesNavigationProperties = this.ExpandDerivedTypesNavigationProperties,
CustomXMLAttributesMapping = this.CustomXMLAttributesMapping,
CustomHttpMethodLinkRelMapping = this.CustomHttpMethodLinkRelMapping,
AppendBoundOperationsOnDerivedTypeCastSegments = this.AppendBoundOperationsOnDerivedTypeCastSegments,
UseSuccessStatusCodeRange = this.UseSuccessStatusCodeRange
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

namespace Microsoft.OpenApi.OData.Operation
{
Expand All @@ -19,6 +21,19 @@ internal class EdmActionOperationHandler : EdmOperationOperationHandler
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Post;

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
base.SetBasicInfo(operation);

// Description
var insertRestrictions = Context.Model.GetRecord<InsertRestrictionsType>(EdmOperation, CapabilitiesConstants.InsertRestrictions);
if (!string.IsNullOrWhiteSpace(insertRestrictions?.LongDescription))
{
operation.Description = insertRestrictions.LongDescription;
}
}

/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;

namespace Microsoft.OpenApi.OData.Operation
{
Expand All @@ -23,6 +25,19 @@ internal class EdmFunctionOperationHandler : EdmOperationOperationHandler
/// </summary>
public IEdmFunction Function => EdmOperation as IEdmFunction;

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
base.SetBasicInfo(operation);

// Description
var readRestrictions = Context.Model.GetRecord<ReadRestrictionsType>(EdmOperation, CapabilitiesConstants.ReadRestrictions);
if (!string.IsNullOrWhiteSpace(readRestrictions?.LongDescription))
{
operation.Description = readRestrictions.LongDescription;
}
}

/// <inheritdoc/>
protected override void SetExtensions(OpenApiOperation operation)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
using Microsoft.OpenApi.OData.Vocabulary.Core;

namespace Microsoft.OpenApi.OData.Operation
{
Expand Down Expand Up @@ -152,5 +153,18 @@ internal static string PathAsString(IEnumerable<string> path)
{
return String.Join("/", path);
}

/// <inheritdoc/>
protected override void SetExternalDocs(OpenApiOperation operation)
{
if (Context.Settings.ShowExternalDocs && Context.Model.GetLinkRecord(EdmOperationImport, CustomLinkRel) is Link externalDocs)
{
operation.ExternalDocs = new OpenApiExternalDocs()
{
Description = CoreConstants.ExternalDocsDescription,
Url = externalDocs.Href
};
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
using Microsoft.OpenApi.OData.Vocabulary.Core;

namespace Microsoft.OpenApi.OData.Operation
{
Expand Down Expand Up @@ -42,9 +43,7 @@ internal abstract class EdmOperationOperationHandler : OperationHandler

/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
base.Initialize(context, path);

{
// It's bound operation, the first segment must be the navigaiton source.
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
NavigationSource = navigationSourceSegment.NavigationSource;
Expand All @@ -53,6 +52,8 @@ protected override void Initialize(ODataContext context, ODataPath path)
EdmOperation = OperationSegment.Operation;

HasTypeCast = path.Segments.Any(s => s is ODataTypeCastSegment);

base.Initialize(context, path);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -198,5 +199,30 @@ protected override void AppendCustomParameters(OpenApiOperation operation)
AppendCustomParameters(operation, restriction.CustomQueryOptions, ParameterLocation.Query);
}
}

/// <inheritdoc/>
protected override void SetCustomLinkRelType()
{
if (Context.Settings.CustomHttpMethodLinkRelMapping != null && EdmOperation != null)
{
LinkRelKey key = EdmOperation.IsAction() ? LinkRelKey.Action : LinkRelKey.Function;
Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out string linkRelValue);
CustomLinkRel = linkRelValue;
}
}


/// <inheritdoc/>
protected override void SetExternalDocs(OpenApiOperation operation)
{
if (Context.Settings.ShowExternalDocs && Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel) is Link externalDocs)
{
operation.ExternalDocs = new OpenApiExternalDocs()
{
Description = CoreConstants.ExternalDocsDescription,
Url = externalDocs.Href
};
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Core;

namespace Microsoft.OpenApi.OData.Operation
{
Expand Down Expand Up @@ -56,5 +57,18 @@ protected override void SetExtensions(OpenApiOperation operation)

base.SetExtensions(operation);
}

/// <inheritdoc/>
protected override void SetExternalDocs(OpenApiOperation operation)
{
if (Context.Settings.ShowExternalDocs && Context.Model.GetLinkRecord(EntitySet, CustomLinkRel) is Link externalDocs)
{
operation.ExternalDocs = new OpenApiExternalDocs()
{
Description = CoreConstants.ExternalDocsDescription,
Url = externalDocs.Href
};
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
using Microsoft.OpenApi.OData.Vocabulary.Core;
using System.Collections.Generic;
using System.Linq;

Expand All @@ -24,7 +25,7 @@ internal abstract class MediaEntityOperationalHandler : NavigationPropertyOperat
/// Gets/Sets the NavigationSource segment
/// </summary>
protected ODataNavigationSourceSegment NavigationSourceSegment { get; private set; }

/// <summary>
/// Gets/Sets flag indicating whether path is navigation property path
/// </summary>
Expand Down Expand Up @@ -204,5 +205,18 @@ private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType,
{
return entityType.DeclaredNavigationProperties().FirstOrDefault(x => x.Name.Equals(identifier));
}

protected override void SetExternalDocs(OpenApiOperation operation)
{
if (Context.Settings.ShowExternalDocs && IsNavigationPropertyPath &&
Context.Model.GetLinkRecord(NavigationProperty, CustomLinkRel) is Link externalDocs)
{
operation.ExternalDocs = new OpenApiExternalDocs()
{
Description = CoreConstants.ExternalDocsDescription,
Url = externalDocs.Href
};
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Vocabulary;
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
using Microsoft.OpenApi.OData.Vocabulary.Core;

namespace Microsoft.OpenApi.OData.Operation
{
Expand Down Expand Up @@ -156,6 +157,19 @@ protected string GetOperationId(string prefix = null)
return string.Join(".", items);
}

/// <inheritdoc/>
protected override void SetExternalDocs(OpenApiOperation operation)
{
if (Context.Settings.ShowExternalDocs && Context.Model.GetLinkRecord(NavigationProperty, CustomLinkRel) is Link externalDocs)
{
operation.ExternalDocs = new OpenApiExternalDocs()
{
Description = CoreConstants.ExternalDocsDescription,
Url = externalDocs.Href
};
}
}

/// <summary>
/// Retrieves the CRUD restrictions annotations for the navigation property
/// in context, given a capability annotation term.
Expand Down
Loading