Skip to content

Add support for PUT operation on entity sets and navigation properties based on UpdateMethod annotation #166

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 10 commits into from
Feb 8, 2022
Merged
17 changes: 16 additions & 1 deletion docs/csdl/TripService.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@
<Property Name="Name" Type="Edm.String" />
<Property Name="IcaoCode" Type="Edm.String" Nullable="false" />
<Property Name="IataCode" Type="Edm.String" />
<Property Name="Location" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation" />
<Property Name="Location" Type="Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation">
<Annotation Term="Org.OData.Capabilities.V1.UpdateRestrictions">
<Record>
<PropertyValue Property="UpdateMethod">
<EnumMember>Org.OData.Capabilities.V1.HttpMethod/PUT</EnumMember>
</PropertyValue>
</Record>
</Annotation>
</Property>
</EntityType>
<ComplexType Name="Location">
<Property Name="Address" Type="Edm.String" />
Expand Down Expand Up @@ -154,6 +162,13 @@
<PropertyPath>Name</PropertyPath>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Capabilities.V1.UpdateRestrictions">
<Record>
<PropertyValue Property="UpdateMethod">
<EnumMember>Org.OData.Capabilities.V1.HttpMethod/PUT</EnumMember>
</PropertyValue>
</Record>
</Annotation>
</EntitySet>
<EntitySet Name="Airports" EntityType="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Airport" />
<EntitySet Name="NewComePeople" EntityType="Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,116 +3,12 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
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;

internal class ComplexPropertyPatchOperationHandler : ComplexPropertyBaseOperationHandler
internal class ComplexPropertyPatchOperationHandler : ComplexPropertyUpdateOperationHandler
{
/// <inheritdoc />
public override OperationType OperationType => OperationType.Patch;

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = $"Update property {ComplexPropertySegment.Property.Name} value.";

// Description
operation.Description = Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property);

// OperationId
if (Context.Settings.EnableOperationId)
{
string typeName = ComplexPropertySegment.ComplexType.Name;
operation.OperationId = ComplexPropertySegment.Property.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
}
}

/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
OpenApiSchema schema = ComplexPropertySegment.Property.Type.IsCollection() ?
new OpenApiSchema
{
Type = "array",
Items = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.FullName()
}
}
}
:
new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.FullName()
}
};

operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New property values",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = schema
}
}
}
};

base.SetRequestBody(operation);
}

/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}
protected override void SetSecurity(OpenApiOperation operation)
{
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
if (update == null || update.Permissions == null)
{
return;
}

operation.Security = Context.CreateSecurityRequirements(update.Permissions).ToList();
}

protected override void AppendCustomParameters(OpenApiOperation operation)
{
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
if (update == null)
{
return;
}

if (update.CustomHeaders != null)
{
AppendCustomParameters(operation, update.CustomHeaders, ParameterLocation.Header);
}

if (update.CustomQueryOptions != null)
{
AppendCustomParameters(operation, update.CustomQueryOptions, ParameterLocation.Query);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using Microsoft.OpenApi.Models;

namespace Microsoft.OpenApi.OData.Operation;

internal class ComplexPropertyPutOperationHandler : ComplexPropertyUpdateOperationHandler
{
/// <inheritdoc />
public override OperationType OperationType => OperationType.Put;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
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;

internal abstract class ComplexPropertyUpdateOperationHandler : ComplexPropertyBaseOperationHandler
{
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = $"Update property {ComplexPropertySegment.Property.Name} value.";

// Description
operation.Description = Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property);

// OperationId
if (Context.Settings.EnableOperationId)
{
string typeName = ComplexPropertySegment.ComplexType.Name;
operation.OperationId = ComplexPropertySegment.Property.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
}
}

/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
OpenApiSchema schema = ComplexPropertySegment.Property.Type.IsCollection() ?
new OpenApiSchema
{
Type = "array",
Items = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.FullName()
}
}
}
:
new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.FullName()
}
};

operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New property values",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = schema
}
}
}
};

base.SetRequestBody(operation);
}

/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}
protected override void SetSecurity(OpenApiOperation operation)
{
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
if (update == null || update.Permissions == null)
{
return;
}

operation.Security = Context.CreateSecurityRequirements(update.Permissions).ToList();
}

protected override void AppendCustomParameters(OpenApiOperation operation)
{
UpdateRestrictionsType update = Context.Model.GetRecord<UpdateRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions);
if (update == null)
{
return;
}

if (update.CustomHeaders != null)
{
AppendCustomParameters(operation, update.CustomHeaders, ParameterLocation.Header);
}

if (update.CustomQueryOptions != null)
{
AppendCustomParameters(operation, update.CustomQueryOptions, ParameterLocation.Query);
}
}
}
Loading