diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs b/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs index 570aff78..9288d1cf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs @@ -45,6 +45,16 @@ internal static class Constants /// public static string StatusCodeDefault = "default"; + /// + /// Status code class: 4XX + /// + public static string StatusCodeClass4XX = "4XX"; + + /// + /// Status code class: 5XX + /// + public static string StatusCodeClass5XX = "5XX"; + /// /// Edm model error extension key. /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs new file mode 100644 index 00000000..9888e452 --- /dev/null +++ b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs @@ -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; + +/// +/// Extensions methods for the OpenApiOperation class. +/// +public static class OpenApiOperationExtensions +{ + /// + /// 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. + /// + /// The operation. + /// The settings. + /// Whether to add a 204 no content response. + 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()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiErrorSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiErrorSchemaGenerator.cs index e8d93a66..a79e3f96 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiErrorSchemaGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiErrorSchemaGenerator.cs @@ -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; @@ -26,18 +28,20 @@ public static IDictionary CreateODataErrorSchemas(this OD { Utils.CheckArgumentNull(context, nameof(context)); - IDictionary schemas = new Dictionary(); - - // odata.error - schemas.Add("odata.error", CreateErrorSchema()); + return new Dictionary() + { + // 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) } + }; } /// @@ -70,6 +74,31 @@ public static OpenApiSchema CreateErrorSchema() }; } + /// + /// 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. + /// + /// The OData to Open API context. + /// The inner error schema definition. + 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" + }; + } + /// /// Create for "odata.error.main". /// @@ -86,13 +115,13 @@ public static OpenApiSchema CreateErrorMainSchema() Properties = new Dictionary { { - "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", @@ -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" + } } } } @@ -137,13 +169,13 @@ public static OpenApiSchema CreateErrorDetailSchema() Properties = new Dictionary { { - "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, } } } }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index d68dc5b7..4d85996f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -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" + } + } + } }; /// @@ -41,8 +59,7 @@ internal static class OpenApiResponseGenerator /// The created . public static OpenApiResponse GetResponse(this string statusCode) { - OpenApiResponse response; - if (_responses.TryGetValue(statusCode, out response)) + if (_responses.TryGetValue(statusCode, out OpenApiResponse response)) { return response; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs index e551c27d..217789b5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs @@ -50,6 +50,10 @@ public static IDictionary 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; @@ -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); diff --git a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs index 5770b484..7f3dcc3a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs @@ -215,6 +215,16 @@ public string PathPrefix /// public bool AddEnumDescriptionExtension { get; set; } = false; + /// + /// Gets/sets a value indicating whether the error responses should be described as a default response or as 4XX and 5XX error responses. + /// + public bool ErrorResponsesAsDefault { get; set; } = true; + + /// + /// Gets/Sets the name of the complex type to look for in the main namespace to use as the inner error type. + /// + public string InnerErrorComplexTypeName { get; set; } = "InnerError"; + internal OpenApiConvertSettings Clone() { var newSettings = new OpenApiConvertSettings @@ -251,6 +261,8 @@ internal OpenApiConvertSettings Clone() RequireDerivedTypesConstraintForODataTypeCastSegments = this.RequireDerivedTypesConstraintForODataTypeCastSegments, EnableDeprecationInformation = this.EnableDeprecationInformation, AddEnumDescriptionExtension = this.AddEnumDescriptionExtension, + ErrorResponsesAsDefault = this.ErrorResponsesAsDefault, + InnerErrorComplexTypeName = this.InnerErrorComplexTypeName }; return newSettings; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyDeleteOperationHandler.cs index 6a1fa552..3b25b527 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyDeleteOperationHandler.cs @@ -55,12 +55,7 @@ protected override void SetParameters(OpenApiOperation operation) /// 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) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs index 28a0b798..4d00f98a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs @@ -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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs index 010e73b4..808a2a16 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs @@ -83,12 +83,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs index e834194d..0416c4bb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs @@ -96,12 +96,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs index c48851fa..c229358e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs @@ -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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs index 79b638cc..53ff6d98 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs @@ -62,12 +62,7 @@ protected override void SetParameters(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs index 3be5b2bb..59b3fb34 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs @@ -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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs index 463094f7..b4a7e157 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs @@ -86,12 +86,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs index 15d233de..fc3ea9b5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs @@ -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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index 381fd56b..22a266fc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs index 510baa94..86afaa06 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs @@ -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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs index 6e1bfe69..d9138518 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs @@ -61,12 +61,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs index 0e20519d..6eaf138d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs @@ -69,7 +69,7 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs index e86b8e38..376aa1a3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs @@ -67,12 +67,7 @@ protected override void SetSecurity(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index b11adaee..0656486a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -138,7 +138,7 @@ protected override void SetResponses(OpenApiOperation operation) }; } - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs index 56ac7340..112eadb1 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs @@ -81,12 +81,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs index cca8c45e..03581b56 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs @@ -120,7 +120,7 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs index 88f75b44..d25b720e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs @@ -176,7 +176,7 @@ protected override void SetResponses(OpenApiOperation operation) else SetCollectionResponse(operation); - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs index ec68f984..a217a74b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs @@ -81,12 +81,7 @@ protected override void SetSecurity(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs index 98a66ac6..65625ab0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs @@ -122,7 +122,7 @@ protected override void SetResponses(OpenApiOperation operation) }; } - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs index ede32705..f2b08ba2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs @@ -91,7 +91,7 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs index 279b672b..ce41cf42 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs @@ -65,12 +65,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs index b81d714f..73364fbc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs @@ -111,7 +111,7 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse()); + operation.AddErrorResponses(Context.Settings, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs index 677308df..a1aadc84 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs @@ -83,12 +83,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// 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); } diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 62ac6f8b..a721f3b3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -181,6 +181,10 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.get Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.get -> string override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Identifier.get -> string override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType @@ -271,4 +275,6 @@ Microsoft.OpenApi.OData.OpenApiExtensions.OpenApiDeprecationExtension.RemovalDat Microsoft.OpenApi.OData.OpenApiExtensions.OpenApiDeprecationExtension.RemovalDate.set -> void Microsoft.OpenApi.OData.OpenApiExtensions.OpenApiDeprecationExtension.Date.get -> System.DateTime? Microsoft.OpenApi.OData.OpenApiExtensions.OpenApiDeprecationExtension.Date.set -> void -Microsoft.OpenApi.OData.OpenApiExtensions.OpenApiDeprecationExtension.Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) -> void \ No newline at end of file +Microsoft.OpenApi.OData.OpenApiExtensions.OpenApiDeprecationExtension.Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) -> void +Microsoft.OpenApi.OData.Common.OpenApiOperationExtensions +static Microsoft.OpenApi.OData.Common.OpenApiOperationExtensions.AddErrorResponses(this Microsoft.OpenApi.Models.OpenApiOperation operation, Microsoft.OpenApi.OData.OpenApiConvertSettings settings, bool addNoContent = false) -> void diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/OpenApiOperationExtensionsTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/OpenApiOperationExtensionsTests.cs new file mode 100644 index 00000000..576677d2 --- /dev/null +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/OpenApiOperationExtensionsTests.cs @@ -0,0 +1,55 @@ +// ------------------------------------------------------------ +// 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 Xunit; +using Microsoft.OpenApi.OData.Common; + +namespace Microsoft.OpenApi.OData.Tests; + +public class OpenApiOperationExtensionsTests +{ + [Theory] + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public void AddsErrorResponses(bool addNoContent, bool errorAsDefault) + { + // Arrange + var settings = new OpenApiConvertSettings { + ErrorResponsesAsDefault = errorAsDefault, + }; + var operation = new OpenApiOperation(); + + // Act + operation.AddErrorResponses(settings, addNoContent); + + // Assert + Assert.NotNull(operation.Responses); + Assert.Equal((errorAsDefault ? 1 : 2) + (addNoContent ? 1 : 0), operation.Responses.Count); + + if(addNoContent) + { + Assert.True(operation.Responses.ContainsKey("204")); + } + else + { + Assert.False(operation.Responses.ContainsKey("204")); + } + if(errorAsDefault) + { + Assert.True(operation.Responses.ContainsKey("default")); + Assert.False(operation.Responses.ContainsKey("4XX")); + Assert.False(operation.Responses.ContainsKey("5XX")); + } + else + { + Assert.False(operation.Responses.ContainsKey("default")); + Assert.True(operation.Responses.ContainsKey("4XX")); + Assert.True(operation.Responses.ContainsKey("5XX")); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiErrorSchemaGeneraratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiErrorSchemaGeneraratorTests.cs new file mode 100644 index 00000000..ed67c1a7 --- /dev/null +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiErrorSchemaGeneraratorTests.cs @@ -0,0 +1,46 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------ + +using Microsoft.OData.Edm; +using Microsoft.OpenApi.OData.Edm; +using Microsoft.OpenApi.OData.Generator; +using Xunit; + +namespace Microsoft.OpenApi.OData.Tests; +public class OpenApiErrorSchemaGeneraratorTests +{ + [Fact] + public void AddsEmptyInnerErrorWhenNoComplexTypeIsProvided() + { + IEdmModel model = EdmModelHelper.ContractServiceModel; + OpenApiConvertSettings settings = new() + { + ErrorResponsesAsDefault = false, + }; + ODataContext context = new(model, settings); + + var schema = OpenApiErrorSchemaGenerator.CreateInnerErrorSchema(context); + + Assert.Equal("object", schema.Type); + Assert.Empty(schema.Properties); + } + [Fact] + public void AddsInnerErrorPropertiesWhenComplexTypeIsProvided() + { + IEdmModel model = EdmModelHelper.TripServiceModel; + OpenApiConvertSettings settings = new() + { + ErrorResponsesAsDefault = false, + }; + ODataContext context = new(model, settings); + + var schema = OpenApiErrorSchemaGenerator.CreateInnerErrorSchema(context); + + Assert.Equal("object", schema.Type); + Assert.NotEmpty(schema.Properties); + Assert.Contains("Date", schema.Properties.Keys); + Assert.Contains("RequestId", schema.Properties.Keys); + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json index 4faf1be7..393958e8 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.json @@ -2274,8 +2274,7 @@ } }, "innererror": { - "description": "The structure of this object is service-specific", - "type": "object" + "$ref": "#/definitions/odata.error.innererror" } } }, @@ -2297,6 +2296,10 @@ } } }, + "odata.error.innererror": { + "description": "The structure of this object is service-specific", + "type": "object" + }, "ODataCountResponse": { "format": "int32", "type": "integer" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml index 01acdf95..a5a03553 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.V2.yaml @@ -1511,8 +1511,7 @@ definitions: items: $ref: '#/definitions/odata.error.detail' innererror: - description: The structure of this object is service-specific - type: object + $ref: '#/definitions/odata.error.innererror' odata.error.detail: required: - code @@ -1525,6 +1524,9 @@ definitions: type: string target: type: string + odata.error.innererror: + description: The structure of this object is service-specific + type: object ODataCountResponse: format: int32 type: integer diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json index 3fee0719..0133ff42 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.json @@ -2512,7 +2512,8 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true }, "details": { "type": "array", @@ -2521,8 +2522,7 @@ } }, "innererror": { - "type": "object", - "description": "The structure of this object is service-specific" + "$ref": "#/components/schemas/odata.error.innererror" } } }, @@ -2540,10 +2540,15 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true } } }, + "odata.error.innererror": { + "type": "object", + "description": "The structure of this object is service-specific" + }, "ODataCountResponse": { "type": "integer", "format": "int32" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml index df737205..6f52f937 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Basic.OpenApi.yaml @@ -1668,13 +1668,13 @@ components: type: string target: type: string + nullable: true details: type: array items: $ref: '#/components/schemas/odata.error.detail' innererror: - type: object - description: The structure of this object is service-specific + $ref: '#/components/schemas/odata.error.innererror' odata.error.detail: required: - code @@ -1687,6 +1687,10 @@ components: type: string target: type: string + nullable: true + odata.error.innererror: + type: object + description: The structure of this object is service-specific ODataCountResponse: type: integer format: int32 diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json index 14425f18..37f8e330 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.json @@ -45,8 +45,7 @@ } }, "innererror": { - "description": "The structure of this object is service-specific", - "type": "object" + "$ref": "#/definitions/odata.error.innererror" } } }, @@ -68,6 +67,10 @@ } } }, + "odata.error.innererror": { + "description": "The structure of this object is service-specific", + "type": "object" + }, "ODataCountResponse": { "format": "int32", "type": "integer" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml index efa5bec8..30b316e6 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.V2.yaml @@ -32,8 +32,7 @@ definitions: items: $ref: '#/definitions/odata.error.detail' innererror: - description: The structure of this object is service-specific - type: object + $ref: '#/definitions/odata.error.innererror' odata.error.detail: required: - code @@ -46,6 +45,9 @@ definitions: type: string target: type: string + odata.error.innererror: + description: The structure of this object is service-specific + type: object ODataCountResponse: format: int32 type: integer diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json index 22cc046b..095be6b5 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.json @@ -38,7 +38,8 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true }, "details": { "type": "array", @@ -47,8 +48,7 @@ } }, "innererror": { - "type": "object", - "description": "The structure of this object is service-specific" + "$ref": "#/components/schemas/odata.error.innererror" } } }, @@ -66,10 +66,15 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true } } }, + "odata.error.innererror": { + "type": "object", + "description": "The structure of this object is service-specific" + }, "ODataCountResponse": { "type": "integer", "format": "int32" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml index 9d53bdd0..2aab48d6 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Empty.OpenApi.yaml @@ -27,13 +27,13 @@ components: type: string target: type: string + nullable: true details: type: array items: $ref: '#/components/schemas/odata.error.detail' innererror: - type: object - description: The structure of this object is service-specific + $ref: '#/components/schemas/odata.error.innererror' odata.error.detail: required: - code @@ -46,6 +46,10 @@ components: type: string target: type: string + nullable: true + odata.error.innererror: + type: object + description: The structure of this object is service-specific ODataCountResponse: type: integer format: int32 diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json index f66c7d63..a7c5062c 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.json @@ -5849,8 +5849,7 @@ } }, "innererror": { - "description": "The structure of this object is service-specific", - "type": "object" + "$ref": "#/definitions/odata.error.innererror" } } }, @@ -5872,6 +5871,10 @@ } } }, + "odata.error.innererror": { + "description": "The structure of this object is service-specific", + "type": "object" + }, "ODataCountResponse": { "format": "int32", "type": "integer" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml index 4e0dd01d..2c68f0ed 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.V2.yaml @@ -4291,8 +4291,7 @@ definitions: items: $ref: '#/definitions/odata.error.detail' innererror: - description: The structure of this object is service-specific - type: object + $ref: '#/definitions/odata.error.innererror' odata.error.detail: required: - code @@ -4305,6 +4304,9 @@ definitions: type: string target: type: string + odata.error.innererror: + description: The structure of this object is service-specific + type: object ODataCountResponse: format: int32 type: integer diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json index 890b832b..df40ed0c 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.json @@ -6569,7 +6569,8 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true }, "details": { "type": "array", @@ -6578,8 +6579,7 @@ } }, "innererror": { - "type": "object", - "description": "The structure of this object is service-specific" + "$ref": "#/components/schemas/odata.error.innererror" } } }, @@ -6597,10 +6597,15 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true } } }, + "odata.error.innererror": { + "type": "object", + "description": "The structure of this object is service-specific" + }, "ODataCountResponse": { "type": "integer", "format": "int32" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml index e8f30d87..33254da9 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/Multiple.Schema.OpenApi.yaml @@ -4771,13 +4771,13 @@ components: type: string target: type: string + nullable: true details: type: array items: $ref: '#/components/schemas/odata.error.detail' innererror: - type: object - description: The structure of this object is service-specific + $ref: '#/components/schemas/odata.error.innererror' odata.error.detail: required: - code @@ -4790,6 +4790,10 @@ components: type: string target: type: string + nullable: true + odata.error.innererror: + type: object + description: The structure of this object is service-specific ODataCountResponse: type: integer format: int32 diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OData.xml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OData.xml index ab636673..4e10c635 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OData.xml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OData.xml @@ -2,6 +2,10 @@ + + + + diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json index fce7d605..fccfe902 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.json @@ -28773,8 +28773,7 @@ } }, "innererror": { - "description": "The structure of this object is service-specific", - "type": "object" + "$ref": "#/definitions/odata.error.innererror" } } }, @@ -28796,6 +28795,20 @@ } } }, + "odata.error.innererror": { + "title": "InnerError", + "type": "object", + "properties": { + "Date": { + "format": "date-time", + "pattern": "^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$", + "type": "string" + }, + "RequestId": { + "type": "string" + } + } + }, "ODataCountResponse": { "format": "int32", "type": "integer" diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml index 0bdaee62..bc1c5648 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.V2.yaml @@ -20376,8 +20376,7 @@ definitions: items: $ref: '#/definitions/odata.error.detail' innererror: - description: The structure of this object is service-specific - type: object + $ref: '#/definitions/odata.error.innererror' odata.error.detail: required: - code @@ -20390,6 +20389,16 @@ definitions: type: string target: type: string + odata.error.innererror: + title: InnerError + type: object + properties: + Date: + format: date-time + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + RequestId: + type: string ODataCountResponse: format: int32 type: integer diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json index 127be552..affb4044 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.json @@ -32233,7 +32233,8 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true }, "details": { "type": "array", @@ -32242,8 +32243,7 @@ } }, "innererror": { - "type": "object", - "description": "The structure of this object is service-specific" + "$ref": "#/components/schemas/odata.error.innererror" } } }, @@ -32261,7 +32261,24 @@ "type": "string" }, "target": { - "type": "string" + "type": "string", + "nullable": true + } + } + }, + "odata.error.innererror": { + "title": "InnerError", + "type": "object", + "properties": { + "Date": { + "pattern": "^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$", + "type": "string", + "format": "date-time", + "nullable": true + }, + "RequestId": { + "type": "string", + "nullable": true } } }, @@ -32614,6 +32631,12 @@ } }, "examples": { + "Microsoft.OData.Service.Sample.TrippinInMemory.Models.InnerError": { + "value": { + "Date": "0001-01-01T00:00:00.0000000+00:00", + "RequestId": "String" + } + }, "Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person": { "value": { "AddressInfo": [ diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml index 396afddf..81e79dfe 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Resources/TripService.OpenApi.yaml @@ -22454,13 +22454,13 @@ components: type: string target: type: string + nullable: true details: type: array items: $ref: '#/components/schemas/odata.error.detail' innererror: - type: object - description: The structure of this object is service-specific + $ref: '#/components/schemas/odata.error.innererror' odata.error.detail: required: - code @@ -22473,6 +22473,19 @@ components: type: string target: type: string + nullable: true + odata.error.innererror: + title: InnerError + type: object + properties: + Date: + pattern: '^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$' + type: string + format: date-time + nullable: true + RequestId: + type: string + nullable: true ODataCountResponse: type: integer format: int32 @@ -22700,6 +22713,10 @@ components: schema: type: string examples: + Microsoft.OData.Service.Sample.TrippinInMemory.Models.InnerError: + value: + Date: '0001-01-01T00:00:00.0000000+00:00' + RequestId: String Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person: value: AddressInfo: