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

adds the ability to define error responses on error codes instead of default #167

Merged
merged 7 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ internal static class Constants
/// </summary>
public static string StatusCodeDefault = "default";

/// <summary>
/// Status code class: 4XX
/// </summary>
public static string StatusCodeClass4XX = "4XX";

/// <summary>
/// Status code class: 5XX
/// </summary>
public static string StatusCodeClass5XX = "5XX";

/// <summary>
/// Edm model error extension key.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// ------------------------------------------------------------
// 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;
using Microsoft.OpenApi.OData.Generator;

namespace Microsoft.OpenApi.OData.Common;

/// <summary>
/// Extensions methods for the OpenApiOperation class.
/// </summary>
public static class OpenApiOperationExtensions
{
/// <summary>
/// Adds a default response to the operation or 4XX/5XX responses for the errors depending on the settings.
/// Also adds a 204 no content response when requested.
/// </summary>
/// <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)
{
if (operation == null) {
throw Error.ArgumentNull(nameof(operation));
}
if(settings == null) {
throw Error.ArgumentNull(nameof(settings));
}

if(operation.Responses == null)
{
operation.Responses = new();
}

if(addNoContent)
{
operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
}

if(settings.ErrorResponsesAsDefault)
{
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
else
{
operation.Responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse());
operation.Responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// ------------------------------------------------------------

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;
Expand All @@ -26,18 +28,20 @@ public static IDictionary<string, OpenApiSchema> CreateODataErrorSchemas(this OD
{
Utils.CheckArgumentNull(context, nameof(context));

IDictionary<string, OpenApiSchema> schemas = new Dictionary<string, OpenApiSchema>();

// odata.error
schemas.Add("odata.error", CreateErrorSchema());
return new Dictionary<string, OpenApiSchema>()
{
// odata.error
{ "odata.error", CreateErrorSchema() },

// odata.error.main
schemas.Add("odata.error.main", CreateErrorMainSchema());
// odata.error.main
{ "odata.error.main", CreateErrorMainSchema() },

// odata.error.detail
schemas.Add("odata.error.detail", CreateErrorDetailSchema());
// odata.error.detail
{ "odata.error.detail", CreateErrorDetailSchema() },

return schemas;
// odata.error.innererror
{ "odata.error.innererror", CreateInnerErrorSchema(context) }
};
}

/// <summary>
Expand Down Expand Up @@ -70,6 +74,31 @@ public static OpenApiSchema CreateErrorSchema()
};
}

/// <summary>
/// Creates the inner error schema definition. If an "InnerError" complex type is defined in the root namespace, then this type will be used as the inner error type.
/// Otherwise, a default inner error type of object will be created.
/// </summary>
/// <param name="context">The OData to Open API context.</param>
/// <returns>The inner error schema definition.</returns>
public static OpenApiSchema CreateInnerErrorSchema(ODataContext context)
{
Utils.CheckArgumentNull(context, nameof(context));

var rootNamespace = context.Model.DeclaredNamespaces.OrderBy(n => n.Count(x => x == '.')).FirstOrDefault();
if(!string.IsNullOrEmpty(context.Settings.InnerErrorComplexTypeName) &&
!string.IsNullOrEmpty(rootNamespace) &&
context.Model.FindDeclaredType($"{rootNamespace}.{context.Settings.InnerErrorComplexTypeName}") is IEdmComplexType complexType)
{
return context.CreateSchemaTypeSchema(complexType);
}

return new OpenApiSchema
{
Type = "object",
Description = "The structure of this object is service-specific"
};
}

/// <summary>
/// Create <see cref="OpenApiSchema"/> for "odata.error.main".
/// </summary>
Expand All @@ -86,13 +115,13 @@ public static OpenApiSchema CreateErrorMainSchema()
Properties = new Dictionary<string, OpenApiSchema>
{
{
"code", new OpenApiSchema { Type = "string" }
"code", new OpenApiSchema { Type = "string", Nullable = false }
},
{
"message", new OpenApiSchema { Type = "string" }
"message", new OpenApiSchema { Type = "string", Nullable = false, }
},
{
"target", new OpenApiSchema { Type = "string" }
"target", new OpenApiSchema { Type = "string", Nullable = true }
},
{
"details",
Expand All @@ -113,8 +142,11 @@ public static OpenApiSchema CreateErrorMainSchema()
"innererror",
new OpenApiSchema
{
Type = "object",
Description = "The structure of this object is service-specific"
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = "odata.error.innererror"
}
}
}
}
Expand All @@ -137,13 +169,13 @@ public static OpenApiSchema CreateErrorDetailSchema()
Properties = new Dictionary<string, OpenApiSchema>
{
{
"code", new OpenApiSchema { Type = "string" }
"code", new OpenApiSchema { Type = "string", Nullable = false, }
},
{
"message", new OpenApiSchema { Type = "string" }
"message", new OpenApiSchema { Type = "string", Nullable = false, }
},
{
"target", new OpenApiSchema { Type = "string" }
"target", new OpenApiSchema { Type = "string", Nullable = true, }
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ internal static class OpenApiResponseGenerator
},

{ Constants.StatusCode204, new OpenApiResponse { Description = "Success"} },
{ Constants.StatusCodeClass4XX, new OpenApiResponse
{
Reference = new OpenApiReference
{
Type = ReferenceType.Response,
Id = "error"
}
}
},
{ Constants.StatusCodeClass5XX, new OpenApiResponse
{
Reference = new OpenApiReference
{
Type = ReferenceType.Response,
Id = "error"
}
}
}
};

/// <summary>
Expand All @@ -41,8 +59,7 @@ internal static class OpenApiResponseGenerator
/// <returns>The created <see cref="OpenApiResponse"/>.</returns>
public static OpenApiResponse GetResponse(this string statusCode)
{
OpenApiResponse response;
if (_responses.TryGetValue(statusCode, out response))
if (_responses.TryGetValue(statusCode, out OpenApiResponse response))
{
return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public static IDictionary<string, OpenApiSchema> CreateSchemas(this ODataContext
case EdmSchemaElementKind.TypeDefinition: // Type definition
{
IEdmType reference = (IEdmType)element;
if(reference is IEdmComplexType &&
reference.FullTypeName().EndsWith(context.Settings.InnerErrorComplexTypeName, StringComparison.Ordinal))
continue;

schemas.Add(reference.FullTypeName(), context.CreateSchemaTypeSchema(reference));
}
break;
Expand Down Expand Up @@ -340,7 +344,7 @@ public static OpenApiSchema CreateSchemaTypeDefinitionSchema(this ODataContext c
return context.CreateSchema(typeDefinition.UnderlyingType);
}

private static OpenApiSchema CreateSchemaTypeSchema(this ODataContext context, IEdmType edmType)
internal static OpenApiSchema CreateSchemaTypeSchema(this ODataContext context, IEdmType edmType)
{
Debug.Assert(context != null);
Debug.Assert(edmType != null);
Expand Down
12 changes: 12 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,16 @@ public string PathPrefix
/// </summary>
public bool AddEnumDescriptionExtension { get; set; } = false;

/// <summary>
/// Gets/sets a value indicating whether the error responses should be described as a default response or as 4XX and 5XX error responses.
baywet marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public bool ErrorResponsesAsDefault { get; set; } = true;

/// <summary>
/// Gets/Sets the name of the complex type to look for in the main namespace to use as the inner error type.
/// </summary>
public string InnerErrorComplexTypeName { get; set; } = "InnerError";

internal OpenApiConvertSettings Clone()
{
var newSettings = new OpenApiConvertSettings
Expand Down Expand Up @@ -251,6 +261,8 @@ internal OpenApiConvertSettings Clone()
RequireDerivedTypesConstraintForODataTypeCastSegments = this.RequireDerivedTypesConstraintForODataTypeCastSegments,
EnableDeprecationInformation = this.EnableDeprecationInformation,
AddEnumDescriptionExtension = this.AddEnumDescriptionExtension,
ErrorResponsesAsDefault = this.ErrorResponsesAsDefault,
InnerErrorComplexTypeName = this.InnerErrorComplexTypeName
};

return newSettings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,7 @@ protected override void SetParameters(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};

operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}
protected override void SetSecurity(OpenApiOperation operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ protected override void SetResponses(OpenApiOperation operation)
SetCollectionResponse(operation);
else
SetSingleResponse(operation);
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,7 @@ protected override void SetRequestBody(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};

operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}
protected override void SetSecurity(OpenApiOperation operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,7 @@ protected override void SetRequestBody(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};

operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ protected override void SetResponses(OpenApiOperation operation)
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,7 @@ protected override void SetParameters(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};

operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ protected override void SetResponses(OpenApiOperation operation)
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,7 @@ protected override void SetRequestBody(OpenApiOperation operation)
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};

operation.AddErrorResponses(Context.Settings, true);
base.SetResponses(operation);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ protected override void SetResponses(OpenApiOperation operation)
}
};

operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected override void SetResponses(OpenApiOperation operation)
}
};

operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected override void SetResponses(OpenApiOperation operation)
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
operation.AddErrorResponses(Context.Settings, false);

base.SetResponses(operation);
}
Expand Down
Loading