Skip to content

Commit

Permalink
Provides support for using the range of response status code 2XX (#215
Browse files Browse the repository at this point in the history
)

* UseHTTPStatusCodeClass2XX as a setting to rep. all status codes 200-299

* Implement UseStatusCodeClass2XX setting when generating responses

* Update tests to validate use of the setting: UseHTTPStatusCodeClass2XX

* Rename property

* Update tests

* Add schema to responses with 2XX status code; return 204 status code for actions/functions

* Rename field variables appropriately

* Update csproj with project release notes; fix missing comma
  • Loading branch information
irvinesunday authored Jun 6, 2022
1 parent fba1c33 commit 079f8ea
Show file tree
Hide file tree
Showing 49 changed files with 604 additions and 427 deletions.
5 changes: 5 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ internal static class Constants
/// </summary>
public static string ApplicationOctetStreamMediaType = "application/octet-stream";

/// <summary>
/// Status code class: 2XX
/// </summary>
public static string StatusCodeClass2XX = "2XX";

/// <summary>
/// Status code: 200
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Generator;
using System.Collections.Generic;

namespace Microsoft.OpenApi.OData.Common;

Expand All @@ -20,7 +21,8 @@ public static class OpenApiOperationExtensions
/// <param name="operation">The operation.</param>
/// <param name="settings">The settings.</param>
/// <param name="addNoContent">Whether to add a 204 no content response.</param>
public static void AddErrorResponses(this OpenApiOperation operation, OpenApiConvertSettings settings, bool addNoContent = false)
/// <param name="schema">Optional: The OpenAPI schema of the response.</param>
public static void AddErrorResponses(this OpenApiOperation operation, OpenApiConvertSettings settings, bool addNoContent = false, OpenApiSchema schema = null)
{
if (operation == null) {
throw Error.ArgumentNull(nameof(operation));
Expand All @@ -34,9 +36,29 @@ public static void AddErrorResponses(this OpenApiOperation operation, OpenApiCon
operation.Responses = new();
}

if(addNoContent)
if (addNoContent)
{
operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
if (settings.UseSuccessStatusCodeRange && schema != null)
{
OpenApiResponse response = new()
{
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = schema
}
}
}
};
operation.Responses.Add(Constants.StatusCodeClass2XX, response);
}
else
{
operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
}
}

if(settings.ErrorResponsesAsDefault)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp
}
}
};
responses.Add(Constants.StatusCode200, response);
responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response);
}

if (context.Settings.ErrorResponsesAsDefault)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<PackageId>Microsoft.OpenApi.OData</PackageId>
<SignAssembly>true</SignAssembly>
<Version>1.0.11-preview1</Version>
<Version>1.0.11-preview2</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 list of all derived types for discriminator mapping #219
- Fixes reading restriction annotations for entity types defining navigation properties #220
- Enables configuring appending bound operations on derived types #221
- Add error ranges for OData actions when ErrorResponsesAsDefault is set to false #218
- Fixes missing bound operations on some navigation property paths #201
- Provides support for using success status code range 2XX #153
</PackageReleaseNotes>
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
<AssemblyOriginatorKeyFile>..\..\tool\Microsoft.OpenApi.OData.snk</AssemblyOriginatorKeyFile>
Expand Down
9 changes: 8 additions & 1 deletion src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ public string PathPrefix
/// </summary>
public bool AppendBoundOperationsOnDerivedTypeCastSegments { get; set; } = false;

/// <summary>
/// Gets/Sets a value indicating whether or not to use the HTTP success status code range 2XX
/// to represent all response codes between 200 - 299.
/// </summary>
public bool UseSuccessStatusCodeRange { get; set; } = false;

internal OpenApiConvertSettings Clone()
{
var newSettings = new OpenApiConvertSettings
Expand Down Expand Up @@ -294,7 +300,8 @@ internal OpenApiConvertSettings Clone()
RequireRestrictionAnnotationsToGenerateComplexPropertyPaths = this.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths,
ExpandDerivedTypesNavigationProperties = this.ExpandDerivedTypesNavigationProperties,
CustomXMLAttributesMapping = this.CustomXMLAttributesMapping,
AppendBoundOperationsOnDerivedTypeCastSegments = this.AppendBoundOperationsOnDerivedTypeCastSegments
AppendBoundOperationsOnDerivedTypeCastSegments = this.AppendBoundOperationsOnDerivedTypeCastSegments,
UseSuccessStatusCodeRange = this.UseSuccessStatusCodeRange
};

return newSettings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ internal class ComplexPropertyGetOperationHandler : ComplexPropertyBaseOperation
/// <inheritdoc />
public override OperationType OperationType => OperationType.Get;

/// <summary>
/// Gets/Sets the <see cref="ReadRestrictionsType"/>
/// </summary>
private ReadRestrictionsType ReadRestrictions { get; set; }
private ReadRestrictionsType _readRestrictions;

protected override void Initialize(ODataContext context, ODataPath path)
{
base.Initialize(context, path);

ReadRestrictions = Context.Model.GetRecord<ReadRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions);
_readRestrictions = Context.Model.GetRecord<ReadRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions);
}

/// <inheritdoc/>
Expand All @@ -45,8 +42,8 @@ protected override void SetBasicInfo(OpenApiOperation operation)

// Summary and Description
string placeHolder = $"Get {ComplexPropertySegment.Property.Name} property value";
operation.Summary = ReadRestrictions?.Description ?? placeHolder;
operation.Description = ReadRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property);
operation.Summary = _readRestrictions?.Description ?? placeHolder;
operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property);

base.SetBasicInfo(operation);
}
Expand Down Expand Up @@ -155,7 +152,7 @@ private void SetCollectionResponse(OpenApiOperation operation)
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode200,
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
UnresolvedReference = true,
Expand Down Expand Up @@ -187,7 +184,7 @@ private void SetSingleResponse(OpenApiOperation operation)
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode200,
Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200,
new OpenApiResponse
{
Description = "Result entities",
Expand All @@ -207,29 +204,29 @@ private void SetSingleResponse(OpenApiOperation operation)
}
protected override void SetSecurity(OpenApiOperation operation)
{
if (ReadRestrictions?.Permissions == null)
if (_readRestrictions?.Permissions == null)
{
return;
}

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

protected override void AppendCustomParameters(OpenApiOperation operation)
{
if (ReadRestrictions == null)
if (_readRestrictions == null)
{
return;
}

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

if (ReadRestrictions.CustomQueryOptions != null)
if (_readRestrictions.CustomQueryOptions != null)
{
AppendCustomParameters(operation, ReadRestrictions.CustomQueryOptions, ParameterLocation.Query);
AppendCustomParameters(operation, _readRestrictions.CustomQueryOptions, ParameterLocation.Query);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,12 @@ protected override void Initialize(ODataContext context, ODataPath path)
throw new InvalidOperationException("OData conventions do not support POSTing to a complex property that is not a collection.");
}

InsertRestrictions = Context.Model.GetRecord<InsertRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.InsertRestrictions);
_insertRestrictions = Context.Model.GetRecord<InsertRestrictionsType>(ComplexPropertySegment.Property, CapabilitiesConstants.InsertRestrictions);
}
/// <inheritdoc />
public override OperationType OperationType => OperationType.Post;

/// <summary>
/// Gets/Sets the <see cref="InsertRestrictionsType"/>
/// </summary>
private InsertRestrictionsType InsertRestrictions { get; set; }
private InsertRestrictionsType _insertRestrictions;

/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
Expand All @@ -48,8 +45,8 @@ protected override void SetBasicInfo(OpenApiOperation operation)

// Summary and Description
string placeHolder = $"Sets a new value for the collection of {ComplexPropertySegment.ComplexType.Name}.";
operation.Summary = InsertRestrictions?.Description ?? placeHolder;
operation.Description = InsertRestrictions?.LongDescription;
operation.Summary = _insertRestrictions?.Description ?? placeHolder;
operation.Description = _insertRestrictions?.LongDescription;

base.SetBasicInfo(operation);
}
Expand All @@ -72,20 +69,7 @@ protected override void SetParameters(OpenApiOperation operation)
}
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
OpenApiSchema schema = new()
{
Type = "array",
Items = new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.FullName()
}
}
};
{
operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Expand All @@ -95,7 +79,7 @@ protected override void SetRequestBody(OpenApiOperation operation)
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = schema
Schema = GetOpenApiSchema()
}
}
}
Expand All @@ -106,35 +90,52 @@ protected override void SetRequestBody(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.AddErrorResponses(Context.Settings, true);
operation.AddErrorResponses(Context.Settings, true, GetOpenApiSchema());
base.SetResponses(operation);
}

protected override void SetSecurity(OpenApiOperation operation)
{
if (InsertRestrictions?.Permissions == null)
if (_insertRestrictions?.Permissions == null)
{
return;
}

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

protected override void AppendCustomParameters(OpenApiOperation operation)
{
if (InsertRestrictions == null)
if (_insertRestrictions == null)
{
return;
}

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

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

private OpenApiSchema GetOpenApiSchema()
{
return new()
{
Type = "array",
Items = new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = ComplexPropertySegment.ComplexType.FullName()
}
}
};
}
}
Loading

0 comments on commit 079f8ea

Please sign in to comment.