Example #1
0
        /// <summary>
        /// Reads the stream input and parses it into an Open API document.
        /// </summary>
        /// <param name="input">Stream containing OpenAPI description to parse.</param>
        /// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
        /// <returns>Instance of newly created OpenApiDocument</returns>
        public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
        {
            ParsingContext context;
            YamlDocument   yamlDocument;

            diagnostic = new OpenApiDiagnostic();

            // Parse the YAML/JSON
            try
            {
                yamlDocument = LoadYamlDocument(input);
            }
            catch (SyntaxErrorException ex)
            {
                diagnostic.Errors.Add(new OpenApiReaderError(ex));
                return(new OpenApiDocument());
            }

            context = new ParsingContext
            {
                ExtensionParsers = _settings.ExtensionParsers
            };

            OpenApiDocument document = null;

            try
            {
                // Parse the OpenAPI Document
                document = context.Parse(yamlDocument, diagnostic);

                // Resolve References if requested
                switch (_settings.ReferenceResolution)
                {
                case ReferenceResolutionSetting.ResolveAllReferences:
                    throw new ArgumentException(Properties.SRResource.CannotResolveRemoteReferencesSynchronously);

                case ReferenceResolutionSetting.ResolveLocalReferences:
                    var resolver = new OpenApiReferenceResolver(document);
                    var walker   = new OpenApiWalker(resolver);
                    walker.Walk(document);
                    foreach (var item in resolver.Errors)
                    {
                        diagnostic.Errors.Add(item);
                    }
                    break;

                case ReferenceResolutionSetting.DoNotResolveReferences:
                    break;
                }
            }
            catch (OpenApiException ex)
            {
                diagnostic.Errors.Add(new OpenApiError(ex));
            }

            // Validate the document
            var errors = document.Validate(_settings.RuleSet);

            foreach (var item in errors)
            {
                diagnostic.Errors.Add(item);
            }

            return(document);
        }
        public void ValidateAnyOfCompositeSchemaMustContainPropertySpecifiedInTheDiscriminator()
        {
            IEnumerable <OpenApiError> errors;
            var schema = new OpenApiSchema
            {
                Type  = "object",
                AnyOf = new List <OpenApiSchema>
                {
                    new OpenApiSchema
                    {
                        Type       = "object",
                        Properties =
                        {
                            ["property1"] = new OpenApiSchema()
                            {
                            Type = "integer", Format = "int64"
                            },
                            ["property2"] = new OpenApiSchema()
                            {
                            Type = "string"
                            }
                        },
                        Reference = new OpenApiReference {
                            Id = "schema1"
                        }
                    },
                    new OpenApiSchema
                    {
                        Type       = "object",
                        Properties =
                        {
                            ["property1"] = new OpenApiSchema()
                            {
                            Type = "integer", Format = "int64"
                            },
                        },
                        Reference = new OpenApiReference {
                            Id = "schema2"
                        }
                    }
                },
                Discriminator = new OpenApiDiscriminator
                {
                    PropertyName = "property2"
                }
            };

            // Act
            var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
            var walker    = new OpenApiWalker(validator);

            walker.Walk(schema);

            errors = validator.Errors;
            bool result = !errors.Any();

            // Assert
            result.Should().BeFalse();
            errors.ShouldAllBeEquivalentTo(new List <OpenApiValidatorError>
            {
                new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateAnyOfDiscriminator), "#/anyOf",
                                          string.Format(SRResource.Validation_CompositeSchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator,
                                                        "schema1", "property2")),

                new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateAnyOfDiscriminator), "#/anyOf",
                                          string.Format(SRResource.Validation_CompositeSchemaMustContainPropertySpecifiedInTheDiscriminator,
                                                        "schema2", "property2")),

                new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateAnyOfDiscriminator), "#/anyOf",
                                          string.Format(SRResource.Validation_CompositeSchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator,
                                                        "schema2", "property2")),
            });
        }
        public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema()
        {
            // Arrange
            IEnumerable <OpenApiError> errors;

            var parameter = new OpenApiParameter()
            {
                Name     = "parameter1",
                In       = ParameterLocation.Path,
                Required = true,
                Schema   = new OpenApiSchema()
                {
                    Type = "object",
                    AdditionalProperties = new OpenApiSchema()
                    {
                        Type = "integer",
                    }
                },
                Examples =
                {
                    ["example0"] = new OpenApiExample()
                        {
                        Value = new OpenApiString("1"),
                        },
                    ["example1"] = new OpenApiExample()
                        {
                        Value = new OpenApiObject()
                        {
                        ["x"] = new OpenApiInteger(2),
                        ["y"] = new OpenApiString("20"),
                        ["z"] = new OpenApiString("200")
                        }
                        },
                    ["example2"] = new OpenApiExample()
                        {
                        Value =
                            new OpenApiArray()
                        {
                        new OpenApiInteger(3)
                        }
                        },
                    ["example3"] = new OpenApiExample()
                        {
                        Value = new OpenApiObject()
                        {
                        ["x"] = new OpenApiInteger(4),
                        ["y"] = new OpenApiInteger(40),
                        }
                        },
                }
            };

            // Act
            var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
            var walker    = new OpenApiWalker(validator);

            walker.Walk(parameter);

            errors = validator.Errors;
            bool result = !errors.Any();

            // Assert
            result.Should().BeFalse();
            errors.Select(e => e.Message).Should().BeEquivalentTo(new[]
            {
                RuleHelpers.DataTypeMismatchedErrorMessage,
                RuleHelpers.DataTypeMismatchedErrorMessage,
                RuleHelpers.DataTypeMismatchedErrorMessage,
            });
            errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[]
            {
                // #enum/0 is not an error since the spec allows
                // representing an object using a string.
                "#/examples/example1/value/y",
                "#/examples/example1/value/z",
                "#/examples/example2/value"
            });
        }
        public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema()
        {
            // Arrange
            IEnumerable <OpenApiError> errors;
            var schema = new OpenApiSchema()
            {
                Type       = "object",
                Properties =
                {
                    ["property1"] = new OpenApiSchema()
                            {
                            Type  = "array",
                            Items = new OpenApiSchema()
                            {
                            Type   = "integer",
                            Format = "int64"
                            }
                            },
                    ["property2"] = new OpenApiSchema()
                            {
                            Type  = "array",
                            Items = new OpenApiSchema()
                            {
                            Type = "object",
                            AdditionalProperties = new OpenApiSchema()
                            {
                            Type = "boolean"
                            }
                            }
                            },
                    ["property3"] = new OpenApiSchema()
                            {
                            Type   = "string",
                            Format = "password"
                            },
                    ["property4"] = new OpenApiSchema()
                            {
                            Type = "string"
                            }
                },
                Default = new OpenApiObject()
                {
                    ["property1"] = new OpenApiArray()
                    {
                        new OpenApiInteger(12),
                        new OpenApiLong(13),
                        new OpenApiString("1"),
                    },
                    ["property2"] = new OpenApiArray()
                    {
                        new OpenApiInteger(2),
                        new OpenApiObject()
                        {
                            ["x"] = new OpenApiBoolean(true),
                            ["y"] = new OpenApiBoolean(false),
                            ["z"] = new OpenApiString("1234"),
                        }
                    },
                    ["property3"] = new OpenApiPassword("123"),
                    ["property4"] = new OpenApiDateTime(DateTime.UtcNow)
                }
            };

            // Act
            var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
            var walker    = new OpenApiWalker(validator);

            walker.Walk(schema);

            errors = validator.Errors;
            bool result = !errors.Any();

            // Assert
            result.Should().BeFalse();
            errors.Select(e => e.Message).Should().BeEquivalentTo(new[]
            {
                RuleHelpers.DataTypeMismatchedErrorMessage,
                RuleHelpers.DataTypeMismatchedErrorMessage,
                RuleHelpers.DataTypeMismatchedErrorMessage,
                RuleHelpers.DataTypeMismatchedErrorMessage,
                RuleHelpers.DataTypeMismatchedErrorMessage,
            });
            errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[]
            {
                "#/default/property1/0",
                "#/default/property1/2",
                "#/default/property2/0",
                "#/default/property2/1/z",
                "#/default/property4",
            });
        }
        public void LocateReferences()
        {
            var baseSchema = new OpenApiSchema()
            {
                Reference = new OpenApiReference()
                {
                    Id   = "base",
                    Type = ReferenceType.Schema
                },
                UnresolvedReference = false
            };

            var derivedSchema = new OpenApiSchema
            {
                AnyOf = new List <OpenApiSchema>()
                {
                    baseSchema
                },
                Reference = new OpenApiReference()
                {
                    Id   = "derived",
                    Type = ReferenceType.Schema
                },
                UnresolvedReference = false
            };

            var testHeader = new OpenApiHeader()
            {
                Schema    = derivedSchema,
                Reference = new OpenApiReference()
                {
                    Id   = "test-header",
                    Type = ReferenceType.Header
                },
                UnresolvedReference = false
            };

            var doc = new OpenApiDocument
            {
                Paths = new OpenApiPaths()
                {
                    ["/"] = new OpenApiPathItem()
                    {
                        Operations = new Dictionary <OperationType, OpenApiOperation>()
                        {
                            [OperationType.Get] = new OpenApiOperation()
                            {
                                Responses = new OpenApiResponses()
                                {
                                    ["200"] = new OpenApiResponse()
                                    {
                                        Content = new Dictionary <string, OpenApiMediaType>()
                                        {
                                            ["application/json"] = new OpenApiMediaType()
                                            {
                                                Schema = derivedSchema
                                            }
                                        },
                                        Headers = new Dictionary <string, OpenApiHeader>()
                                        {
                                            ["test-header"] = testHeader
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                Components = new OpenApiComponents()
                {
                    Schemas = new Dictionary <string, OpenApiSchema>()
                    {
                        ["derived"] = derivedSchema,
                        ["base"]    = baseSchema,
                    },
                    Headers = new Dictionary <string, OpenApiHeader>()
                    {
                        ["test-header"] = testHeader
                    }
                }
            };

            var locator = new LocatorVisitor();
            var walker  = new OpenApiWalker(locator);

            walker.Walk(doc);

            locator.Locations.Where(l => l.StartsWith("referenceAt:")).Should().BeEquivalentTo(new List <string> {
                "referenceAt: #/paths/~1/get/responses/200/content/application~1json/schema",
                "referenceAt: #/paths/~1/get/responses/200/headers/test-header",
                "referenceAt: #/components/schemas/derived/anyOf/0",
                "referenceAt: #/components/headers/test-header/schema"
            });
        }