-
Notifications
You must be signed in to change notification settings - Fork 67
Expand file tree
/
Copy pathOpenApiErrorSchemaGenerator.cs
More file actions
182 lines (171 loc) · 8.36 KB
/
OpenApiErrorSchemaGenerator.cs
File metadata and controls
182 lines (171 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// ------------------------------------------------------------
// 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.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.MicrosoftExtensions;
namespace Microsoft.OpenApi.OData.Generator
{
/// <summary>
/// Create <see cref="OpenApiSchema"/> for Edm spatial types.
/// </summary>
internal static class OpenApiErrorSchemaGenerator
{
internal const string ODataErrorClassName = "ODataError";
internal const string MainErrorClassName = "MainError";
internal const string ErrorDetailsClassName = "ErrorDetails";
internal const string InnerErrorClassName = "InnerError";
/// <summary>
/// Create the dictionary of <see cref="OpenApiSchema"/> object.
/// The name of each pair is the namespace-qualified name of the type. It uses the namespace instead of the alias.
/// The value of each pair is a <see cref="OpenApiSchema"/>.
/// </summary>
/// <param name="context">The OData to Open API context.</param>
/// <param name="document">The Open API document to lookup references.</param>
/// <returns>The string/schema dictionary.</returns>
public static IDictionary<string, IOpenApiSchema> CreateODataErrorSchemas(this ODataContext context, OpenApiDocument document)
{
Utils.CheckArgumentNull(context, nameof(context));
var rootNamespaceName = context.GetErrorNamespaceName();
return new Dictionary<string, IOpenApiSchema>()
{
{ $"{rootNamespaceName}{ODataErrorClassName}", CreateErrorSchema(rootNamespaceName, document) },
{ $"{rootNamespaceName}{MainErrorClassName}", CreateErrorMainSchema(rootNamespaceName, document) },
{ $"{rootNamespaceName}{ErrorDetailsClassName}", CreateErrorDetailSchema() },
{ $"{rootNamespaceName}{InnerErrorClassName}", CreateInnerErrorSchema(context, document) }
};
}
/// <summary>
/// Gets the error namespace name based on the root namespace of the model.
/// </summary>
/// <param name="context">The OData to Open API context.</param>
/// <returns>The error namespace name.</returns>
public static string GetErrorNamespaceName(this ODataContext context) {
Utils.CheckArgumentNull(context, nameof(context));
var rootNamespaceName = context.Model.DeclaredNamespaces.OrderBy(ns => ns.Count(y => y == '.')).FirstOrDefault();
rootNamespaceName += (string.IsNullOrEmpty(rootNamespaceName) ? string.Empty : ".") +
"ODataErrors.";
return rootNamespaceName;
}
/// <summary>
/// Create <see cref="OpenApiSchema"/> for the error.
/// </summary>
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
/// <param name="rootNamespaceName">The root namespace name. With a trailing dot.</param>
/// <param name="document">The Open API document to lookup references.</param>
public static OpenApiSchema CreateErrorSchema(string rootNamespaceName, OpenApiDocument document)
{
return new OpenApiSchema
{
Type = JsonSchemaType.Object,
Required = new HashSet<string>
{
"error"
},
Properties = new Dictionary<string, IOpenApiSchema>
{
{
"error",
new OpenApiSchemaReference($"{rootNamespaceName}{MainErrorClassName}", document)
}
}
};
}
/// <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>
/// <param name="document">The Open API document to lookup references.</param>
/// <returns>The inner error schema definition.</returns>
public static IOpenApiSchema CreateInnerErrorSchema(ODataContext context, OpenApiDocument document)
{
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, document);
}
return new OpenApiSchema
{
Type = JsonSchemaType.Object,
Description = "The structure of this object is service-specific"
};
}
/// <summary>
/// Create <see cref="OpenApiSchema"/> for main property of the error.
/// </summary>
/// <param name="rootNamespaceName">The root namespace name. With a trailing dot.</param>
/// <param name="document">The Open API document to lookup references.</param>
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateErrorMainSchema(string rootNamespaceName, OpenApiDocument document)
{
return new OpenApiSchema
{
Type = JsonSchemaType.Object,
Required = new HashSet<string>
{
"code", "message"
},
Properties = new Dictionary<string, IOpenApiSchema>
{
{
"code", new OpenApiSchema { Type = JsonSchemaType.String }
},
{
"message", new OpenApiSchema { Type = JsonSchemaType.String, Extensions = new Dictionary<string, IOpenApiExtension>
{ { OpenApiPrimaryErrorMessageExtension.Name, new OpenApiPrimaryErrorMessageExtension { IsPrimaryErrorMessage = true } } } }
},
{
"target", new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null }
},
{
"details",
new OpenApiSchema
{
Type = JsonSchemaType.Array,
Items = new OpenApiSchemaReference($"{rootNamespaceName}{ErrorDetailsClassName}", document)
}
},
{
"innerError",
new OpenApiSchemaReference($"{rootNamespaceName}{InnerErrorClassName}", document)
}
}
};
}
/// <summary>
/// Create <see cref="OpenApiSchema"/> for detail property of the error.
/// </summary>
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateErrorDetailSchema()
{
return new OpenApiSchema
{
Type = JsonSchemaType.Object,
Required = new HashSet<string>
{
"code", "message"
},
Properties = new Dictionary<string, IOpenApiSchema>
{
{
"code", new OpenApiSchema { Type = JsonSchemaType.String, }
},
{
"message", new OpenApiSchema { Type = JsonSchemaType.String, }
},
{
"target", new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, }
}
}
};
}
}
}