diff --git a/Microsoft.OpenApi.sln b/Microsoft.OpenApi.sln
index a8c85bdb4..c4745c45c 100644
--- a/Microsoft.OpenApi.sln
+++ b/Microsoft.OpenApi.sln
@@ -15,9 +15,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Workbench
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Readers", "src\Microsoft.OpenApi.Readers\Microsoft.OpenApi.Readers.csproj", "{79933258-0126-4382-8755-D50820ECC483}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Tests", "test\Microsoft.OpenApi.Tests\Microsoft.OpenApi.Tests.csproj", "{AD83F991-DBF3-4251-8613-9CC54C826964}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Tests", "test\Microsoft.OpenApi.Tests\Microsoft.OpenApi.Tests.csproj", "{AD83F991-DBF3-4251-8613-9CC54C826964}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.OpenApi.Readers.Tests", "test\Microsoft.OpenApi.Readers.Tests\Microsoft.OpenApi.Readers.Tests.csproj", "{1ED3C2C1-E1E7-4925-B4E6-2D969C3F5237}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OpenApi.Readers.Tests", "test\Microsoft.OpenApi.Readers.Tests\Microsoft.OpenApi.Readers.Tests.csproj", "{1ED3C2C1-E1E7-4925-B4E6-2D969C3F5237}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E546B92F-20A8-49C3-8323-4B25BB78F3E1}"
EndProject
diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
index a80282c28..14489c394 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
@@ -5,6 +5,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Expressions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// Callback Object: A map of possible out-of band callbacks related to the parent operation.
///
+ [OpenApiValidator(typeof(CallbackValidator))]
public class OpenApiCallback : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
index 2e719e1ff..7232eee78 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Components Object.
///
+ [OpenApiValidator(typeof(ComponentsValidator))]
public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiContact.cs b/src/Microsoft.OpenApi/Models/OpenApiContact.cs
index 01fca2aa8..cb2b1aeeb 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiContact.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiContact.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// Contact Object.
///
+ [OpenApiValidator(typeof(ContactValidator))]
public class OpenApiContact : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs
index cee77aadb..be9259121 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs
@@ -3,6 +3,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -10,6 +12,7 @@ namespace Microsoft.OpenApi.Models
///
/// Discriminator object.
///
+ [OpenApiValidator(typeof(DiscriminatorValidator))]
public class OpenApiDiscriminator : IOpenApiSerializable
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
index 630f2f86d..3163cf7bd 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
@@ -6,6 +6,8 @@
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -13,6 +15,7 @@ namespace Microsoft.OpenApi.Models
///
/// Describes an Open API Document. See: https://swagger.io/specification
///
+ [OpenApiValidator(typeof(DocumentValidator))]
public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs
index 716d626d5..d98c3c8f1 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiEncoding.cs
@@ -5,6 +5,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// ExternalDocs object.
///
+ [OpenApiValidator(typeof(EncodingValidator))]
public class OpenApiEncoding : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs
index b6baf18c7..28d1dc0e2 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Example Object.
///
+ [OpenApiValidator(typeof(ExampleValidator))]
public class OpenApiExample : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiExternalDocs.cs b/src/Microsoft.OpenApi/Models/OpenApiExternalDocs.cs
index 8e5789bba..d49026f27 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiExternalDocs.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiExternalDocs.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// ExternalDocs object.
///
+ [OpenApiValidator(typeof(ExampleValidator))]
public class OpenApiExternalDocs : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs
index d87b2f73e..43ce9bed2 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs
@@ -5,6 +5,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -13,6 +15,7 @@ namespace Microsoft.OpenApi.Models
/// Header Object.
/// The Header Object follows the structure of the Parameter Object.
///
+ [OpenApiValidator(typeof(HeaderValidator))]
public class OpenApiHeader : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiInfo.cs b/src/Microsoft.OpenApi/Models/OpenApiInfo.cs
index 922ae0818..8d490405f 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiInfo.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiInfo.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// Open API Info Object, it provides the metadata about the Open API.
///
+ [OpenApiValidator(typeof(InfoValidator))]
public class OpenApiInfo : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiLicense.cs b/src/Microsoft.OpenApi/Models/OpenApiLicense.cs
index fc29afba9..192b48386 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiLicense.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiLicense.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// License Object.
///
+ [OpenApiValidator(typeof(LicenseValidator))]
public class OpenApiLicense : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiLink.cs b/src/Microsoft.OpenApi/Models/OpenApiLink.cs
index 83241fd44..ca539f2ad 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiLink.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiLink.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Link Object.
///
+ [OpenApiValidator(typeof(LinkValidator))]
public class OpenApiLink : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs
index 86ab12239..2f076453c 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Media Type Object.
///
+ [OpenApiValidator(typeof(MediaTypeValidator))]
public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiOAuthFlow.cs b/src/Microsoft.OpenApi/Models/OpenApiOAuthFlow.cs
index 54d500128..f873f85fe 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiOAuthFlow.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiOAuthFlow.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// OAuth Flow Object.
///
+ [OpenApiValidator(typeof(OAuthFlowValidator))]
public class OpenApiOAuthFlow : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiOAuthFlows.cs b/src/Microsoft.OpenApi/Models/OpenApiOAuthFlows.cs
index 9fe47e316..bfb43188e 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiOAuthFlows.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiOAuthFlows.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// OAuth Flows Object.
///
+ [OpenApiValidator(typeof(OAuthFlowsValidator))]
public class OpenApiOAuthFlows : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs
index 0548a447c..7205bfb52 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs
@@ -6,6 +6,8 @@
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -13,6 +15,7 @@ namespace Microsoft.OpenApi.Models
///
/// Operation Object.
///
+ [OpenApiValidator(typeof(OperationValidator))]
public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs
index 45272a60c..d3c467c58 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs
@@ -5,6 +5,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// Parameter Object.
///
+ [OpenApiValidator(typeof(ParameterValidator))]
public class OpenApiParameter : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs
index 257d7db30..e5c42c255 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs
@@ -5,6 +5,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// Path Item Object: to describe the operations available on a single path.
///
+ [OpenApiValidator(typeof(PathItemValidator))]
public class OpenApiPathItem : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiPaths.cs b/src/Microsoft.OpenApi/Models/OpenApiPaths.cs
index c998a101a..66405349e 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiPaths.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiPaths.cs
@@ -1,11 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
+
namespace Microsoft.OpenApi.Models
{
///
/// Paths object.
///
+ [OpenApiValidator(typeof(PathsValidator))]
public class OpenApiPaths : OpenApiExtensibleDictionary
{
}
diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs
index ab1b0c20e..b4e84e524 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Request Body Object
///
+ [OpenApiValidator(typeof(RequestBodyValidator))]
public class OpenApiRequestBody : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs
index 591317554..709317970 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs
@@ -5,6 +5,8 @@
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// Response object.
///
+ [OpenApiValidator(typeof(ResponseValidator))]
public class OpenApiResponse : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponses.cs b/src/Microsoft.OpenApi/Models/OpenApiResponses.cs
index 0244d99cf..084f9bbd5 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiResponses.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiResponses.cs
@@ -1,11 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
+
namespace Microsoft.OpenApi.Models
{
///
/// Responses object.
///
+ [OpenApiValidator(typeof(ResponsesValidator))]
public class OpenApiResponses : OpenApiExtensibleDictionary
{
}
diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs
index af586e650..2ea4396c6 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Schema Object.
///
+ [OpenApiValidator(typeof(SchemaValidator))]
public class OpenApiSchema : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs
index a94797b6f..eb8a41a21 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs
@@ -3,6 +3,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -15,6 +17,7 @@ namespace Microsoft.OpenApi.Models
/// then the value is a list of scope names required for the execution.
/// For other security scheme types, the array MUST be empty.
///
+ [OpenApiValidator(typeof(SecurityRequirementValidator))]
public class OpenApiSecurityRequirement : Dictionary>,
IOpenApiSerializable
{
diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
index b9ba59c4d..950421901 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
@@ -6,6 +6,8 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -13,6 +15,7 @@ namespace Microsoft.OpenApi.Models
///
/// Security Scheme Object.
///
+ [OpenApiValidator(typeof(SecuritySchemeValidator))]
public class OpenApiSecurityScheme : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiServer.cs b/src/Microsoft.OpenApi/Models/OpenApiServer.cs
index 3f9ac6c11..e2095fb6c 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiServer.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiServer.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Server Object: an object representing a Server.
///
+ [OpenApiValidator(typeof(ServerValidator))]
public class OpenApiServer : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiServerVariable.cs b/src/Microsoft.OpenApi/Models/OpenApiServerVariable.cs
index 51c44576d..5725f215b 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiServerVariable.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiServerVariable.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Server Variable Object.
///
+ [OpenApiValidator(typeof(ServerVariableValidator))]
public class OpenApiServerVariable : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiTag.cs b/src/Microsoft.OpenApi/Models/OpenApiTag.cs
index fa84da6cb..769ccdf26 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiTag.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiTag.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -11,6 +13,7 @@ namespace Microsoft.OpenApi.Models
///
/// Tag Object.
///
+ [OpenApiValidator(typeof(TagValidator))]
public class OpenApiTag : IOpenApiSerializable, IOpenApiReferenceable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiXml.cs b/src/Microsoft.OpenApi/Models/OpenApiXml.cs
index 1dbd8e310..c34aabff1 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiXml.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiXml.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations;
+using Microsoft.OpenApi.Validations.Validators;
using Microsoft.OpenApi.Writers;
namespace Microsoft.OpenApi.Models
@@ -12,6 +14,7 @@ namespace Microsoft.OpenApi.Models
///
/// XML Object.
///
+ [OpenApiValidator(typeof(XmlValidator))]
public class OpenApiXml : IOpenApiSerializable, IOpenApiExtensible
{
///
diff --git a/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs b/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs
index 2b77e680a..e8f4df444 100644
--- a/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs
+++ b/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs
@@ -239,5 +239,50 @@ internal static string SourceExpressionHasInvalidFormat {
return ResourceManager.GetString("SourceExpressionHasInvalidFormat", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to The key '{0}' in '{1}' of components MUST match the regular expression '{2}'..
+ ///
+ internal static string Validataion_ComponentsKeyMustMatchRegularExpr {
+ get {
+ return ResourceManager.GetString("Validataion_ComponentsKeyMustMatchRegularExpr", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The extension name '{0}' in '{1}' object MUST begin with 'x-'..
+ ///
+ internal static string Validation_ExtensionNameMustBeginWithXDash {
+ get {
+ return ResourceManager.GetString("Validation_ExtensionNameMustBeginWithXDash", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The field '{0}' in '{1}' object is REQUIRED..
+ ///
+ internal static string Validation_FieldIsRequired {
+ get {
+ return ResourceManager.GetString("Validation_FieldIsRequired", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The path item name '{0}' MUST begin with a slash..
+ ///
+ internal static string Validation_PathItemMustBeginWithSlash {
+ get {
+ return ResourceManager.GetString("Validation_PathItemMustBeginWithSlash", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The string '{0}' MUST be in the format of an email address..
+ ///
+ internal static string Validation_StringMustBeEmailAddress {
+ get {
+ return ResourceManager.GetString("Validation_StringMustBeEmailAddress", resourceCulture);
+ }
+ }
}
}
diff --git a/src/Microsoft.OpenApi/Properties/SRResource.resx b/src/Microsoft.OpenApi/Properties/SRResource.resx
index bfffc638c..3f5c2bfbe 100644
--- a/src/Microsoft.OpenApi/Properties/SRResource.resx
+++ b/src/Microsoft.OpenApi/Properties/SRResource.resx
@@ -177,4 +177,19 @@
The source expression '{0}' has invalid format.
+
+ The key '{0}' in '{1}' of components MUST match the regular expression '{2}'.
+
+
+ The extension name '{0}' in '{1}' object MUST begin with 'x-'.
+
+
+ The field '{0}' in '{1}' object is REQUIRED.
+
+
+ The path item name '{0}' MUST begin with a slash.
+
+
+ The string '{0}' MUST be in the format of an email address.
+
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/OpenApiElementValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiElementValidator.cs
new file mode 100644
index 000000000..dcc8b4dcd
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/OpenApiElementValidator.cs
@@ -0,0 +1,74 @@
+// ------------------------------------------------------------
+// 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.OpenApi.Interfaces;
+using Microsoft.OpenApi.Validations.Rules;
+
+namespace Microsoft.OpenApi.Validations
+{
+ ///
+ /// The public APIs to validate the Open API element.
+ ///
+ public static class OpenApiElementValidator
+ {
+ ///
+ /// Validate the Open API element.
+ ///
+ /// The Open API element type.
+ /// The Open API element.
+ /// True means no errors, otherwise with errors.
+ public static bool Validate(this T element) where T : IOpenApiElement
+ {
+ IEnumerable errors;
+ return element.Validate(out errors);
+ }
+
+ ///
+ /// Validate the Open API element.
+ ///
+ /// The Open API element type.
+ /// The Open API element.
+ /// The output errors.
+ /// True means no errors, otherwise with errors.
+ public static bool Validate(this T element, out IEnumerable errors)
+ where T : IOpenApiElement
+ {
+ return element.Validate(null, out errors);
+ }
+
+ ///
+ /// Validate the Open API element.
+ ///
+ /// The Open API element type.
+ /// The Open API element.
+ /// The input rule set.
+ /// The output errors.
+ /// True means no errors, otherwise with errors.
+ public static bool Validate(this T element, ValidationRuleSet ruleSet, out IEnumerable errors)
+ where T : IOpenApiElement
+ {
+ errors = null;
+ if (element == null)
+ {
+ return true;
+ }
+
+ if (ruleSet == null)
+ {
+ ruleSet = ValidationRuleSet.CreateDefaultRuleSet();
+ }
+
+ ValidationContext context = new ValidationContext(ruleSet);
+
+ context.Validate(element);
+
+ errors = context.Errors;
+
+ return !errors.Any();
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidatorAttribute.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidatorAttribute.cs
new file mode 100644
index 000000000..004755107
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/OpenApiValidatorAttribute.cs
@@ -0,0 +1,30 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+
+namespace Microsoft.OpenApi.Validations
+{
+ ///
+ /// The Validator attribute.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
+ public class OpenApiValidatorAttribute : Attribute
+ {
+ ///
+ /// Initializes the class.
+ ///
+ /// The validator type.
+ public OpenApiValidatorAttribute(Type validatorType)
+ {
+ ValidatorType = validatorType ?? throw Error.ArgumentNull(nameof(validatorType));
+ }
+
+ ///
+ /// Gets the validator type.
+ ///
+ public Type ValidatorType { get; }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs
new file mode 100644
index 000000000..d396fc9fe
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs
@@ -0,0 +1,68 @@
+// ------------------------------------------------------------
+// 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.Text.RegularExpressions;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiComponentsRules
+ {
+ ///
+ /// The key regex.
+ ///
+ public static Regex KeyRegex = new Regex(@"^[a-zA-Z0-9\.\-_]+$");
+
+ ///
+ /// All the fixed fields declared above are objects
+ /// that MUST use keys that match the regular expression: ^[a-zA-Z0-9\.\-_]+$.
+ ///
+ public static readonly ValidationRule KeyMustBeRegularExpression =
+ new ValidationRule(
+ (context, components) =>
+ {
+ ValidateKeys(context, components.Schemas?.Keys, "schemas");
+
+ ValidateKeys(context, components.Responses?.Keys, "responses");
+
+ ValidateKeys(context, components.Parameters?.Keys, "parameters");
+
+ ValidateKeys(context, components.Examples?.Keys, "examples");
+
+ ValidateKeys(context, components.RequestBodies?.Keys, "requestBodies");
+
+ ValidateKeys(context, components.Headers?.Keys, "headers");
+
+ ValidateKeys(context, components.SecuritySchemes?.Keys, "securitySchemes");
+
+ ValidateKeys(context, components.Links?.Keys, "links");
+
+ ValidateKeys(context, components.Callbacks?.Keys, "callbacks");
+ });
+
+ private static void ValidateKeys(ValidationContext context, IEnumerable keys, string component)
+ {
+ if (keys == null)
+ {
+ return;
+ }
+
+ foreach(var key in keys)
+ {
+ if (!KeyRegex.IsMatch(key))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Format, context.PathString,
+ string.Format(SRResource.Validataion_ComponentsKeyMustMatchRegularExpr, key, component, KeyRegex.ToString()));
+ context.AddError(error);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs
new file mode 100644
index 000000000..f64ac46c2
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.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 System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ internal static class OpenApiContactRules
+ {
+ ///
+ /// Email field MUST be email address.
+ ///
+ public static readonly ValidationRule EmailMustBeEmailFormat =
+ new ValidationRule(
+ (context, item) =>
+ {
+ context.Push("email");
+ if (item != null && item.Email != null)
+ {
+ if (!item.Email.IsEmailAddress())
+ {
+ ValidationError error = new ValidationError(ErrorReason.Format, context.PathString,
+ String.Format(SRResource.Validation_StringMustBeEmailAddress, item.Email));
+ context.AddError(error);
+ }
+ }
+ context.Pop();
+ });
+
+ ///
+ /// Url field MUST be url format.
+ ///
+ public static readonly ValidationRule UrlMustBeUrlFormat =
+ new ValidationRule(
+ (context, item) =>
+ {
+ context.Push("url");
+ if (item != null && item.Url != null)
+ {
+ // TODO:
+ }
+ context.Pop();
+ });
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs
new file mode 100644
index 000000000..3dd445ee8
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.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 System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ internal static class OpenApiDocumentRules
+ {
+ ///
+ /// The field is required.
+ ///
+ public static readonly ValidationRule FieldIsRequired =
+ new ValidationRule(
+ (context, item) =>
+ {
+ // info
+ context.Push("info");
+ if (item.Info == null)
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "info", "document"));
+ context.AddError(error);
+ }
+ context.Pop();
+
+ // paths
+ context.Push("paths");
+ if (item.Paths == null)
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "paths", "document"));
+ context.AddError(error);
+ }
+ context.Pop();
+ });
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs
new file mode 100644
index 000000000..e74dbe226
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs
@@ -0,0 +1,37 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiExtensibleRules
+ {
+ ///
+ /// Extension name MUST start with "x-".
+ ///
+ public static readonly ValidationRule ExtensionNameMustStartWithXDash =
+ new ValidationRule(
+ (context, item) =>
+ {
+ context.Push("extensions");
+ foreach (var extensible in item.Extensions)
+ {
+ if (!extensible.Key.StartsWith("x-"))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Format, context.PathString,
+ String.Format(SRResource.Validation_ExtensionNameMustBeginWithXDash, extensible.Key, context.PathString));
+ context.AddError(error);
+ }
+ }
+ context.Pop();
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs
new file mode 100644
index 000000000..7bf9803db
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiExternalDocsRules
+ {
+ ///
+ /// REQUIRED. The url of the External Documentation Object.
+ ///
+ public static readonly ValidationRule UrlIsRequired =
+ new ValidationRule(
+ (context, docs) =>
+ {
+ context.Push("url");
+ if (docs.Url == null)
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "url", "External Documentation"));
+ context.AddError(error);
+ }
+ context.Pop();
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs
new file mode 100644
index 000000000..a908e0a81
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs
@@ -0,0 +1,47 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ internal static class OpenApiInfoRules
+ {
+ ///
+ /// Validate the field is required.
+ ///
+ public static readonly ValidationRule FieldIsRequired =
+ new ValidationRule(
+ (context, item) =>
+ {
+ // title
+ context.Push("title");
+ if (String.IsNullOrEmpty(item.Title))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "url", "info"));
+ context.AddError(error);
+ }
+ context.Pop();
+
+ // version
+ context.Push("version");
+ if (String.IsNullOrEmpty(item.Version))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "version", "info"));
+ context.AddError(error);
+ }
+ context.Pop();
+ });
+
+ // add more rule.
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs
new file mode 100644
index 000000000..157c32ab5
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiLicenseRules
+ {
+ ///
+ /// REQUIRED. REQUIRED. The license name used for the API.
+ ///
+ public static readonly ValidationRule FieldIsRequired =
+ new ValidationRule(
+ (context, license) =>
+ {
+ context.Push("name");
+ if (String.IsNullOrEmpty(license.Name))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "name", "license"));
+ context.AddError(error);
+ }
+ context.Pop();
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs
new file mode 100644
index 000000000..437071c13
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.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.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiPathsRules
+ {
+ ///
+ /// A relative path to an individual endpoint. The field name MUST begin with a slash.
+ ///
+ public static readonly ValidationRule PathNameMustBeginWithSlash =
+ new ValidationRule(
+ (context, item) =>
+ {
+ foreach (var pathName in item.Keys)
+ {
+ context.Push(pathName);
+
+ if (string.IsNullOrEmpty(pathName))
+ {
+ // Add the error message
+ // context.Add(...);
+ }
+
+ if (!pathName.StartsWith("/"))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Format, context.PathString,
+ string.Format(SRResource.Validation_PathItemMustBeginWithSlash, pathName));
+ context.AddError(error);
+ }
+
+ context.Pop();
+ }
+ });
+
+ // add more rules
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs
new file mode 100644
index 000000000..f701b0fad
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiServerRules
+ {
+ ///
+ /// REQUIRED. The name of the tag.
+ ///
+ public static readonly ValidationRule FieldIsRequired =
+ new ValidationRule(
+ (context, server) =>
+ {
+ context.Push("url");
+ if (String.IsNullOrEmpty(server.Url))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "url", "Server"));
+ context.AddError(error);
+ }
+ context.Pop();
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs
new file mode 100644
index 000000000..c09436a73
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Properties;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// The validation rules for .
+ ///
+ public static class OpenApiTagRules
+ {
+ ///
+ /// REQUIRED. The name of the tag.
+ ///
+ public static readonly ValidationRule NameIsRequired =
+ new ValidationRule(
+ (context, tag) =>
+ {
+ context.Push("name");
+ if (String.IsNullOrEmpty(tag.Name))
+ {
+ ValidationError error = new ValidationError(ErrorReason.Required, context.PathString,
+ String.Format(SRResource.Validation_FieldIsRequired, "name", "Tag"));
+ context.AddError(error);
+ }
+ context.Pop();
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs
new file mode 100644
index 000000000..780503158
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs
@@ -0,0 +1,40 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ internal static class RuleHelpers
+ {
+ ///
+ /// Input string must be in the format of an email address
+ ///
+ /// The input string.
+ /// True is email address, otherwise false.
+ public static bool IsEmailAddress(this string input)
+ {
+ if (String.IsNullOrEmpty(input))
+ {
+ return false;
+ }
+
+ var splits = input.Split('@');
+ if (splits.Length != 2)
+ {
+ return false;
+ }
+
+ if (String.IsNullOrEmpty(splits[0]) || String.IsNullOrEmpty(splits[1]))
+ {
+ return false;
+ }
+
+ // Add more rules.
+
+ return true;
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Rules/ValidationRule.cs b/src/Microsoft.OpenApi/Validations/Rules/ValidationRule.cs
new file mode 100644
index 000000000..d9575969e
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/ValidationRule.cs
@@ -0,0 +1,48 @@
+
+using System;
+using System.Diagnostics;
+using Microsoft.OpenApi.Interfaces;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ /// Class containing validation rule logic.
+ ///
+ public abstract class ValidationRule
+ {
+ internal abstract Type ValidatedType { get; }
+
+ internal abstract void Evaluate(ValidationContext context, object item);
+ }
+
+ ///
+ /// Class containing validation rule logic for .
+ ///
+ ///
+ public class ValidationRule : ValidationRule
+ where T: IOpenApiElement
+ {
+ private readonly Action _validate;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Action to perform the validation.
+ public ValidationRule(Action validate)
+ {
+ this._validate = validate;
+ }
+
+ internal override Type ValidatedType
+ {
+ get { return typeof(T); }
+ }
+
+ internal override void Evaluate(ValidationContext context, object item)
+ {
+ Debug.Assert(item is T, "item should be " + typeof(T));
+ T typedItem = (T)item;
+ this._validate(context, typedItem);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Rules/ValidationRuleSet.cs b/src/Microsoft.OpenApi/Validations/Rules/ValidationRuleSet.cs
new file mode 100644
index 000000000..8cfdcb650
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Rules/ValidationRuleSet.cs
@@ -0,0 +1,138 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+using Microsoft.OpenApi.Exceptions;
+
+namespace Microsoft.OpenApi.Validations.Rules
+{
+ ///
+ ///
+ ///
+ public sealed class ValidationRuleSet : IEnumerable
+ {
+ private IDictionary> _rules = new Dictionary>();
+
+ private static ValidationRuleSet DefaultRuleSet;
+
+ ///
+ /// The default rule set.
+ ///
+ public static ValidationRuleSet CreateDefaultRuleSet()
+ {
+ if (DefaultRuleSet != null)
+ {
+ return DefaultRuleSet;
+ }
+
+ DefaultRuleSet = new ValidationRuleSet
+ {
+ OpenApiComponentsRules.KeyMustBeRegularExpression,
+
+ OpenApiDocumentRules.FieldIsRequired,
+
+ OpenApiInfoRules.FieldIsRequired,
+
+ OpenApiContactRules.EmailMustBeEmailFormat,
+
+ OpenApiTagRules.NameIsRequired,
+
+ OpenApiExternalDocsRules.UrlIsRequired,
+
+ OpenApiExtensibleRules.ExtensionNameMustStartWithXDash,
+
+ OpenApiLicenseRules.FieldIsRequired,
+
+ OpenApiServerRules.FieldIsRequired,
+
+ OpenApiPathsRules.PathNameMustBeginWithSlash,
+ // add more default rules.
+ };
+
+ return DefaultRuleSet;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ValidationRuleSet()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Rules to be contained in this ruleset.
+ public ValidationRuleSet(IEnumerable rules)
+ {
+ if (rules != null)
+ {
+ foreach (ValidationRule rule in rules)
+ {
+ Add(rule);
+ }
+ }
+ }
+
+ ///
+ /// Gets the rules in this rule set.
+ ///
+ public IEnumerable Rules
+ {
+ get
+ {
+ return _rules.Values.SelectMany(v => v);
+ }
+ }
+
+ ///
+ /// Add the new rule into rule set.
+ ///
+ /// The rule.
+ public void Add(ValidationRule rule)
+ {
+ IList typeRules;
+ if (!_rules.TryGetValue(rule.ValidatedType, out typeRules))
+ {
+ typeRules = new List();
+ _rules[rule.ValidatedType] = typeRules;
+ }
+
+ if (typeRules.Contains(rule))
+ {
+ throw new OpenApiException("The same rule cannot be in the same rule set twice.");
+ }
+
+ typeRules.Add(rule);
+ }
+
+ ///
+ /// Get the enumerator.
+ ///
+ /// The enumerator.
+ public IEnumerator GetEnumerator()
+ {
+ foreach (List ruleList in _rules.Values)
+ {
+ foreach (var rule in ruleList)
+ {
+ yield return rule;
+ }
+ }
+ }
+
+ ///
+ /// Get the enumerator.
+ ///
+ /// The enumerator.
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/ValidationContext.cs b/src/Microsoft.OpenApi/Validations/ValidationContext.cs
new file mode 100644
index 000000000..f5f8cae64
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/ValidationContext.cs
@@ -0,0 +1,81 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using Microsoft.OpenApi.Validations.Rules;
+
+namespace Microsoft.OpenApi.Validations
+{
+ ///
+ /// The validation context.
+ ///
+ public class ValidationContext
+ {
+ private readonly IList _errors = new List();
+
+ ///
+ /// Initializes the class.
+ ///
+ ///
+ public ValidationContext(ValidationRuleSet ruleSet)
+ {
+ RuleSet = ruleSet ?? throw Error.ArgumentNull(nameof(ruleSet));
+ }
+
+ ///
+ /// Gets the rule set.
+ ///
+ public ValidationRuleSet RuleSet { get; }
+
+ ///
+ /// Gets the validation errors.
+ ///
+ public IEnumerable Errors
+ {
+ get
+ {
+ return _errors;
+ }
+ }
+
+ ///
+ /// Register an error with the validation context.
+ ///
+ /// Error to register.
+ public void AddError(ValidationError error)
+ {
+ if (error == null)
+ {
+ throw Error.ArgumentNull(nameof(error));
+ }
+
+ _errors.Add(error);
+ }
+
+ #region Visit Path
+ private readonly Stack _path = new Stack();
+
+ internal void Push(string segment)
+ {
+ this._path.Push(segment);
+ }
+
+ internal void Pop()
+ {
+ this._path.Pop();
+ }
+
+ internal string PathString
+ {
+ get
+ {
+ return "#/" + String.Join("/", _path.Reverse());
+ }
+ }
+ #endregion
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/ValidationContextExtensions.cs b/src/Microsoft.OpenApi/Validations/ValidationContextExtensions.cs
new file mode 100644
index 000000000..c76d0b426
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/ValidationContextExtensions.cs
@@ -0,0 +1,83 @@
+// ------------------------------------------------------------
+// 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.Interfaces;
+using Microsoft.OpenApi.Validations.Validators;
+using System.Collections.Generic;
+
+namespace Microsoft.OpenApi.Validations
+{
+ internal static class ValidationContextExtensions
+ {
+ ///
+ /// Validate the Open API element.
+ ///
+ /// The Open API element.
+ /// The validation cotext.
+ /// The Open API element.
+ public static void Validate(this ValidationContext context, T element) where T : IOpenApiElement
+ {
+ if (context == null)
+ {
+ throw Error.ArgumentNull(nameof(context));
+ }
+
+ if (element != null)
+ {
+ IValidator visitor = OpenApiValidatorCache.GetValidator(typeof(T));
+ if (visitor != null)
+ {
+ visitor.Validate(context, element);
+ }
+ }
+ }
+
+ ///
+ /// Validate the collection of Open API element.
+ ///
+ /// The Open API element.
+ /// The validation cotext.
+ /// The collection of Open API element.
+ public static void ValidateCollection(this ValidationContext context, IEnumerable collection)
+ where T : IOpenApiElement
+ {
+ if (context == null)
+ {
+ throw Error.ArgumentNull(nameof(context));
+ }
+
+ if (collection != null)
+ {
+ foreach (var element in collection)
+ {
+ context.Validate(element);
+ }
+ }
+ }
+
+ ///
+ /// Validate the map of Open API element.
+ ///
+ /// The Open API element.
+ /// The validation cotext.
+ /// The map of Open API element.
+ public static void ValidateMap(this ValidationContext context, IDictionary elements)
+ where T : IOpenApiElement
+ {
+ if (context == null)
+ {
+ throw Error.ArgumentNull(nameof(context));
+ }
+
+ if (elements != null)
+ {
+ foreach (var element in elements)
+ {
+ context.Validate(element.Value);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/ValidationError.cs b/src/Microsoft.OpenApi/Validations/ValidationError.cs
new file mode 100644
index 000000000..19a4ac193
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/ValidationError.cs
@@ -0,0 +1,66 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace Microsoft.OpenApi.Validations
+{
+ ///
+ /// Error reason.
+ ///
+ public enum ErrorReason
+ {
+ ///
+ /// Field is required.
+ ///
+ Required,
+
+ ///
+ /// Format error.
+ ///
+ Format,
+ }
+
+ ///
+ /// The validation error class.
+ ///
+ public sealed class ValidationError
+ {
+ ///
+ /// Initializes the class.
+ ///
+ /// The error reason.
+ /// The visit path.
+ /// The error message.
+ public ValidationError(ErrorReason reason, string path, string message)
+ {
+ ErrorCode = reason;
+ ErrorPath = path;
+ ErrorMessage = message;
+ }
+
+ ///
+ /// Gets the path of the error in the Open API in which it occurred.
+ ///
+ public string ErrorPath { get; private set; }
+
+ ///
+ /// Gets an integer code representing the error.
+ ///
+ public ErrorReason ErrorCode { get; private set; }
+
+ ///
+ /// Gets a human readable string describing the error.
+ ///
+ public string ErrorMessage { get; private set; }
+
+ ///
+ /// Returns the whole error message.
+ ///
+ /// The error string.
+ public override string ToString()
+ {
+ return "ErroCode: " + ErrorCode + ", " + ErrorPath + " | " + ErrorMessage;
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/CallbackValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/CallbackValidator.cs
new file mode 100644
index 000000000..4a3ebdf03
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/CallbackValidator.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class CallbackValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiCallback callback)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(callback != null);
+
+ foreach (var pathItem in callback.PathItems)
+ {
+ context.Validate(pathItem.Value);
+ }
+
+ base.Next(context, callback);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ComponentsValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ComponentsValidator.cs
new file mode 100644
index 000000000..7bdab6419
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ComponentsValidator.cs
@@ -0,0 +1,38 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ComponentsValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiComponents components)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(components != null);
+
+ context.ValidateMap(components.Schemas);
+ context.ValidateMap(components.Responses);
+ context.ValidateMap(components.Parameters);
+ context.ValidateMap(components.Examples);
+ context.ValidateMap(components.RequestBodies);
+ context.ValidateMap(components.Headers);
+ context.ValidateMap(components.SecuritySchemes);
+ context.ValidateMap(components.Links);
+ context.ValidateMap(components.Callbacks);
+ base.Next(context, components);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ContactValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ContactValidator.cs
new file mode 100644
index 000000000..15ac45bfa
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ContactValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ContactValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/DiscriminatorValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/DiscriminatorValidator.cs
new file mode 100644
index 000000000..0c0919574
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/DiscriminatorValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class DiscriminatorValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/DocumentVisitor.cs b/src/Microsoft.OpenApi/Validations/Validators/DocumentVisitor.cs
new file mode 100644
index 000000000..222caca01
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/DocumentVisitor.cs
@@ -0,0 +1,35 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Vistor for
+ ///
+ internal class DocumentValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiDocument document)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(document != null);
+
+ context.Validate(document.Info);
+ context.ValidateCollection(document.Servers);
+ context.Validate(document.Paths);
+ context.Validate(document.Components);
+ context.ValidateCollection(document.SecurityRequirements);
+ context.ValidateCollection(document.Tags);
+ base.Next(context, document);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/EncodingValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/EncodingValidator.cs
new file mode 100644
index 000000000..e3c8efec0
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/EncodingValidator.cs
@@ -0,0 +1,31 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class EncodingValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children in .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiEncoding encoding)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(encoding != null);
+
+ context.ValidateMap(encoding.Headers);
+
+ base.Next(context, encoding);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ExampleValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ExampleValidator.cs
new file mode 100644
index 000000000..47eab7a53
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ExampleValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ExampleValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ExternalDocsValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ExternalDocsValidator.cs
new file mode 100644
index 000000000..13f574b04
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ExternalDocsValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ExternalDocsValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/HeaderValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/HeaderValidator.cs
new file mode 100644
index 000000000..5df8088de
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/HeaderValidator.cs
@@ -0,0 +1,35 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class HeaderValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children in .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiHeader header)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(header != null);
+
+ context.Validate(header.Schema);
+
+ context.ValidateCollection(header.Examples);
+
+ context.ValidateMap(header.Content);
+
+ base.Next(context, header);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/IVisitor.cs b/src/Microsoft.OpenApi/Validations/Validators/IVisitor.cs
new file mode 100644
index 000000000..2236d1868
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/IVisitor.cs
@@ -0,0 +1,20 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// The interface for visitor.
+ ///
+ internal interface IValidator
+ {
+ ///
+ /// Visit the object.
+ ///
+ /// The validation context.
+ /// The validation object.
+ void Validate(ValidationContext context, object item);
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/InfoValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/InfoValidator.cs
new file mode 100644
index 000000000..bddc9ae0e
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/InfoValidator.cs
@@ -0,0 +1,33 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class InfoValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children in .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiInfo info)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(info != null);
+
+ context.Validate(info.Contact);
+
+ context.Validate(info.License);
+
+ base.Next(context, info);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/LicenseValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/LicenseValidator.cs
new file mode 100644
index 000000000..60880df68
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/LicenseValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class LicenseValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/LinkValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/LinkValidator.cs
new file mode 100644
index 000000000..4be2b80de
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/LinkValidator.cs
@@ -0,0 +1,31 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class LinkValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiLink link)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(link != null);
+
+ context.Validate(link.Server);
+
+ base.Next(context, link);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/MediaTypeValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/MediaTypeValidator.cs
new file mode 100644
index 000000000..b2fb92b99
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/MediaTypeValidator.cs
@@ -0,0 +1,33 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class MediaTypeValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiMediaType mediaType)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(mediaType != null);
+
+ context.Validate(mediaType.Schema);
+ context.ValidateMap(mediaType.Examples);
+ context.ValidateMap(mediaType.Encoding);
+
+ base.Next(context, mediaType);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/OAuthFlowValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/OAuthFlowValidator.cs
new file mode 100644
index 000000000..a36c4bb79
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/OAuthFlowValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class OAuthFlowValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/OAuthFlowsValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/OAuthFlowsValidator.cs
new file mode 100644
index 000000000..45a8561f8
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/OAuthFlowsValidator.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class OAuthFlowsValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiOAuthFlows oAuthFlows)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(oAuthFlows != null);
+
+ context.Validate(oAuthFlows.Implicit);
+ context.Validate(oAuthFlows.Password);
+ context.Validate(oAuthFlows.ClientCredentials);
+ context.Validate(oAuthFlows.AuthorizationCode);
+
+ base.Next(context, oAuthFlows);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/OpenApiValidatorCache.cs b/src/Microsoft.OpenApi/Validations/Validators/OpenApiValidatorCache.cs
new file mode 100644
index 000000000..c4e94872b
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/OpenApiValidatorCache.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 System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ internal static class OpenApiValidatorCache
+ {
+ private static IDictionary _elementVisitor = new Dictionary();
+
+ public static IValidator GetValidator(Type elementType)
+ {
+ IValidator validator;
+ if (_elementVisitor.TryGetValue(elementType, out validator))
+ {
+ return validator;
+ }
+
+ var attribute = elementType.GetCustomAttributes(typeof(OpenApiValidatorAttribute), false).FirstOrDefault();
+ if (attribute == null)
+ {
+ return null;
+ }
+
+ OpenApiValidatorAttribute validateAttr = attribute as OpenApiValidatorAttribute;
+ if (validateAttr == null)
+ {
+ return null;
+ }
+
+ object instance = Activator.CreateInstance(validateAttr.ValidatorType);
+ validator = instance as IValidator;
+ if (validator != null)
+ {
+ _elementVisitor[validateAttr.ValidatorType] = validator;
+ }
+
+ return validator;
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/OperationValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/OperationValidator.cs
new file mode 100644
index 000000000..c0e34fb2a
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/OperationValidator.cs
@@ -0,0 +1,38 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class OperationValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiOperation operation)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(operation != null);
+
+ context.ValidateCollection(operation.Tags);
+ context.Validate(operation.ExternalDocs);
+ context.ValidateCollection(operation.Parameters);
+ context.Validate(operation.RequestBody);
+ context.Validate(operation.Responses);
+ context.ValidateMap(operation.Callbacks);
+ context.ValidateCollection(operation.Security);
+ context.ValidateCollection(operation.Servers);
+
+ base.Next(context, operation);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ParameterValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ParameterValidator.cs
new file mode 100644
index 000000000..ae845307f
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ParameterValidator.cs
@@ -0,0 +1,33 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ParameterValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiParameter parameter)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(parameter != null);
+
+ context.Validate(parameter.Schema);
+ context.ValidateCollection(parameter.Examples);
+ context.ValidateMap(parameter.Content);
+
+ base.Next(context, parameter);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/PathItemValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/PathItemValidator.cs
new file mode 100644
index 000000000..b837fa846
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/PathItemValidator.cs
@@ -0,0 +1,37 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class PathItemValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiPathItem pathItem)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(pathItem != null);
+
+ foreach (var operation in pathItem.Operations)
+ {
+ context.Validate(operation.Value);
+ }
+
+ context.ValidateCollection(pathItem.Servers);
+ context.ValidateCollection(pathItem.Parameters);
+
+ base.Next(context, pathItem);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/PathsValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/PathsValidator.cs
new file mode 100644
index 000000000..2f6ea1423
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/PathsValidator.cs
@@ -0,0 +1,30 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class PathsValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiPaths paths)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(paths != null);
+
+ context.ValidateMap(paths);
+ base.Next(context, paths);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/RequestBodyValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/RequestBodyValidator.cs
new file mode 100644
index 000000000..f198efb53
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/RequestBodyValidator.cs
@@ -0,0 +1,31 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class RequestBodyValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiRequestBody requestBody)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(requestBody != null);
+
+ context.ValidateMap(requestBody.Content);
+
+ base.Next(context, requestBody);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ResponseValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ResponseValidator.cs
new file mode 100644
index 000000000..c11674c39
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ResponseValidator.cs
@@ -0,0 +1,33 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ResponseValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiResponse response)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(response != null);
+
+ context.ValidateMap(response.Headers);
+ context.ValidateMap(response.Content);
+ context.ValidateMap(response.Links);
+
+ base.Next(context, response);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ResponsesValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ResponsesValidator.cs
new file mode 100644
index 000000000..9b32af4a3
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ResponsesValidator.cs
@@ -0,0 +1,31 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ResponsesValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiResponses responses)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(responses != null);
+
+ context.ValidateMap(responses);
+
+ base.Next(context, responses);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/SchemaValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/SchemaValidator.cs
new file mode 100644
index 000000000..b77a3aab9
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/SchemaValidator.cs
@@ -0,0 +1,49 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class SchemaValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiSchema schema)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(schema != null);
+
+ context.ValidateCollection(schema.AllOf);
+
+ context.ValidateCollection(schema.OneOf);
+
+ context.ValidateCollection(schema.AnyOf);
+
+ context.Validate(schema.Not);
+
+ context.Validate(schema.Items);
+
+ context.ValidateMap(schema.Properties);
+
+ context.Validate(schema.AdditionalProperties);
+
+ context.Validate(schema.Discriminator);
+
+ context.Validate(schema.ExternalDocs);
+
+ context.Validate(schema.Xml);
+
+ base.Next(context, schema);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/SecurityRequirementValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/SecurityRequirementValidator.cs
new file mode 100644
index 000000000..9bffd2d5a
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/SecurityRequirementValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class SecurityRequirementValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/SecuritySchemeValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/SecuritySchemeValidator.cs
new file mode 100644
index 000000000..0b17dd52c
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/SecuritySchemeValidator.cs
@@ -0,0 +1,32 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class SecuritySchemeValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiSecurityScheme securityScheme)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(securityScheme != null);
+
+ context.Validate(securityScheme.Flows);
+
+ // add more.
+ base.Next(context, securityScheme);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ServerValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ServerValidator.cs
new file mode 100644
index 000000000..89d125dd2
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ServerValidator.cs
@@ -0,0 +1,32 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ServerValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children of the .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiServer server)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(server != null);
+
+ context.ValidateMap(server.Variables);
+
+ // add more.
+ base.Next(context, server);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ServerVariableValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/ServerVariableValidator.cs
new file mode 100644
index 000000000..89494829d
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ServerVariableValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class ServerVariableValidator : ValidatorBase
+ {
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/TagValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/TagValidator.cs
new file mode 100644
index 000000000..e21e93e73
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/TagValidator.cs
@@ -0,0 +1,31 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class TagValidator : ValidatorBase
+ {
+ ///
+ /// Visit the children in .
+ ///
+ /// The validation context.
+ /// The .
+ protected override void Next(ValidationContext context, OpenApiTag tag)
+ {
+ Debug.Assert(context != null);
+ Debug.Assert(tag != null);
+
+ context.Validate(tag.ExternalDocs);
+
+ base.Next(context, tag);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/ValidatorBase.cs b/src/Microsoft.OpenApi/Validations/Validators/ValidatorBase.cs
new file mode 100644
index 000000000..2938bcc0f
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/ValidatorBase.cs
@@ -0,0 +1,56 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System.Diagnostics;
+using System.Linq;
+using Microsoft.OpenApi.Interfaces;
+
+namespace Microsoft.OpenApi.Validations.Validators
+{
+ ///
+ /// The base visitor class for Open Api elements.
+ ///
+ internal abstract class ValidatorBase : IValidator where T : IOpenApiElement
+ {
+ ///
+ /// Visit the element itself.
+ ///
+ /// The validation context.
+ /// The element.
+ public void Validate(ValidationContext context, object item)
+ {
+ Debug.Assert(item is T, "item should be " + typeof(T));
+
+ // validate itself
+ var rules = context.RuleSet.Where(r => r.ValidatedType == typeof(T));
+ foreach (var rule in rules)
+ {
+ rule.Evaluate(context, item);
+ }
+
+ // validate it's children
+ T typedItem = (T)item;
+ this.Next(context, typedItem);
+ }
+
+ ///
+ /// Visit the children.
+ ///
+ /// The validation context.
+ /// The element.
+ protected virtual void Next(ValidationContext context, T element)
+ {
+ IOpenApiExtensible extensbile = element as IOpenApiExtensible;
+ if (extensbile != null)
+ {
+ var rules = context.RuleSet.Where(r => r.ValidatedType == typeof(IOpenApiExtensible));
+ foreach (var rule in rules)
+ {
+ rule.Evaluate(context, extensbile);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Validations/Validators/XmlValidator.cs b/src/Microsoft.OpenApi/Validations/Validators/XmlValidator.cs
new file mode 100644
index 000000000..f0cc70bb3
--- /dev/null
+++ b/src/Microsoft.OpenApi/Validations/Validators/XmlValidator.cs
@@ -0,0 +1,16 @@
+// ------------------------------------------------------------
+// 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.Validations.Validators
+{
+ ///
+ /// Visit .
+ ///
+ internal class XmlValidator : ValidatorBase
+ {
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiContactValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiContactValidationTests.cs
new file mode 100644
index 000000000..f66e4fe07
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiContactValidationTests.cs
@@ -0,0 +1,35 @@
+// ------------------------------------------------------------
+// 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 Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Validations;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.Models
+{
+ public class OpenApiContactValidationTests
+ {
+ [Fact]
+ public void ValidateEmailFieldIsEmailAddressInContact()
+ {
+ // Arrange
+ IEnumerable errors;
+ OpenApiContact Contact = new OpenApiContact()
+ {
+ Email = "support/example.com",
+ };
+
+ // Act
+ bool result = Contact.Validate(out errors);
+
+ // Assert
+ Assert.False(result);
+ Assert.NotNull(errors);
+ ValidationError error = Assert.Single(errors);
+ Assert.Equal("The string 'support/example.com' MUST be in the format of an email address.", error.ErrorMessage);
+ }
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiInfoValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiInfoValidationTests.cs
new file mode 100644
index 000000000..2f89e2d62
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiInfoValidationTests.cs
@@ -0,0 +1,34 @@
+// ------------------------------------------------------------
+// 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.OpenApi.Models;
+using Microsoft.OpenApi.Validations;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.Models
+{
+ public class OpenApiInfoValidationTests
+ {
+ [Fact]
+ public void ValidateFieldIsRequiredInInfo()
+ {
+ // Arrange
+ IEnumerable errors;
+ OpenApiInfo info = new OpenApiInfo();
+
+ // Act
+ bool result = info.Validate(out errors);
+
+ // Assert
+ Assert.False(result);
+ Assert.NotNull(errors);
+
+ Assert.Equal(new[] { "The field 'url' in 'info' object is REQUIRED.",
+ "The field 'version' in 'info' object is REQUIRED."}, errors.Select(e => e.ErrorMessage));
+ }
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiLicenseValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiLicenseValidationTests.cs
new file mode 100644
index 000000000..b6e5225f7
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiLicenseValidationTests.cs
@@ -0,0 +1,32 @@
+// ------------------------------------------------------------
+// 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 Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Validations;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.Models
+{
+ public class OpenApiLicenseValidationTests
+ {
+ [Fact]
+ public void ValidateFieldIsRequiredInLicense()
+ {
+ // Arrange
+ IEnumerable errors;
+ OpenApiLicense license = new OpenApiLicense();
+
+ // Act
+ bool result = license.Validate(out errors);
+
+ // Assert
+ Assert.False(result);
+ Assert.NotNull(errors);
+ ValidationError error = Assert.Single(errors);
+ Assert.Equal("The field 'name' in 'license' object is REQUIRED.", error.ErrorMessage);
+ }
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiServerValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiServerValidationTests.cs
new file mode 100644
index 000000000..9bbf86516
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiServerValidationTests.cs
@@ -0,0 +1,32 @@
+// ------------------------------------------------------------
+// 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 Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Validations;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.Models
+{
+ public class OpenApiServerValidationTests
+ {
+ [Fact]
+ public void ValidateFieldIsRequiredInServer()
+ {
+ // Arrange
+ IEnumerable errors;
+ OpenApiServer server = new OpenApiServer();
+
+ // Act
+ bool result = server.Validate(out errors);
+
+ // Assert
+ Assert.False(result);
+ Assert.NotNull(errors);
+ ValidationError error = Assert.Single(errors);
+ Assert.Equal("The field 'url' in 'Server' object is REQUIRED.", error.ErrorMessage);
+ }
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiTagValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiTagValidationTests.cs
new file mode 100644
index 000000000..2fd1b16bd
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiTagValidationTests.cs
@@ -0,0 +1,54 @@
+// ------------------------------------------------------------
+// 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 Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Validations;
+using Xunit;
+using Microsoft.OpenApi.Any;
+
+namespace Microsoft.OpenApi.Tests.Models
+{
+ public class OpenApiTagValidationTests
+ {
+ [Fact]
+ public void ValidateNameIsRequiredInTag()
+ {
+ // Arrange
+ IEnumerable errors;
+ OpenApiTag tag = new OpenApiTag();
+
+ // Act
+ bool result = tag.Validate(out errors);
+
+ // Assert
+ Assert.False(result);
+ Assert.NotNull(errors);
+ ValidationError error = Assert.Single(errors);
+ Assert.Equal("The field 'name' in 'Tag' object is REQUIRED.", error.ErrorMessage);
+ }
+
+ [Fact]
+ public void ValidateExtensionNameStartsWithXDashInTag()
+ {
+ // Arrange
+ IEnumerable errors;
+ OpenApiTag tag = new OpenApiTag
+ {
+ Name = "tag"
+ };
+ tag.Extensions.Add("tagExt", new OpenApiString("value"));
+
+ // Act
+ bool result = tag.Validate(out errors);
+
+ // Assert
+ Assert.False(result);
+ Assert.NotNull(errors);
+ ValidationError error = Assert.Single(errors);
+ Assert.Equal("The extension name 'tagExt' in '#/extensions' object MUST begin with 'x-'.", error.ErrorMessage);
+ }
+ }
+}