diff --git a/src/Core/Services/OpenAPI/OpenApiDocumentor.cs b/src/Core/Services/OpenAPI/OpenApiDocumentor.cs index 979da52eb6..afb1657d1a 100644 --- a/src/Core/Services/OpenAPI/OpenApiDocumentor.cs +++ b/src/Core/Services/OpenAPI/OpenApiDocumentor.cs @@ -1135,9 +1135,9 @@ private static bool IsRequestBodyRequired(SourceDefinition sourceDef, bool consi StoredProcedureDefinition spDef = (StoredProcedureDefinition)sourceDef; foreach (KeyValuePair parameterMetadata in spDef.Parameters) { - // A parameter which does not have any of the following properties + // A parameter which is explicitly marked required or has no default value // results in the body being required so that a value can be provided. - if (!parameterMetadata.Value.HasConfigDefault) + if (parameterMetadata.Value.Required ?? !parameterMetadata.Value.HasConfigDefault) { requestBodyRequired = true; break; @@ -1422,7 +1422,10 @@ private static OpenApiSchema CreateSpRequestComponentSchema(Dictionary + { + new() { Name = "title", Default = "Sample Title" } + }, + KeyFields: null), + Fields: null, + GraphQL: new(Singular: null, Plural: null, Enabled: false), + Rest: new(Methods: EntityRestOptions.DEFAULT_SUPPORTED_VERBS), + Permissions: OpenApiTestBootstrap.CreateBasicPermissions(), + Mappings: null, + Relationships: null, + Description: "Stored procedure with a parameter default"); + + // Entity whose "title" parameter is explicitly marked required: false in config. + // Even though it has no default value, the explicit override must be honored so that only + // "id" (no default, no override) remains required. + Entity entity3 = new( + Source: new( + Object: "update_book_title", + EntitySourceType.StoredProcedure, + Parameters: new List + { + new() { Name = "title", Required = false } + }, + KeyFields: null), + Fields: null, + GraphQL: new(Singular: null, Plural: null, Enabled: false), + Rest: new(Methods: EntityRestOptions.DEFAULT_SUPPORTED_VERBS), + Permissions: OpenApiTestBootstrap.CreateBasicPermissions(), + Mappings: null, + Relationships: null, + Description: "Stored procedure with an explicit required override"); + Dictionary entities = new() { - { "sp1", entity1 } + { "sp1", entity1 }, + { "sp2", entity2 }, + { "sp3", entity3 } }; _runtimeEntities = new(entities); @@ -74,13 +116,19 @@ public static void CreateEntities() /// /// Validates that the generated request body references stored procedure parameters /// and not result set columns. + /// Also validates that the request body schema component flags the expected parameters + /// as required: a parameter is required when it has no default value and is not explicitly + /// marked required: false in the runtime config. /// /// Entity name /// Expected parameters in request body /// Expected parameter value types in request body. - [DataRow("sp1", new string[] { "title", "publisher_name" }, new string[] { "string", "string" }, DisplayName = "Validate request body parameters and parameter Json data types.")] + /// Expected parameters flagged as required in the schema component. + [DataRow("sp1", new string[] { "title", "publisher_name" }, new string[] { "string", "string" }, new string[] { "title", "publisher_name" }, DisplayName = "Parameters without defaults are all required.")] + [DataRow("sp2", new string[] { "title", "publisher_id" }, new string[] { "string", "integer" }, new string[] { "publisher_id" }, DisplayName = "Parameter with a config default is not required.")] + [DataRow("sp3", new string[] { "id", "title" }, new string[] { "integer", "string" }, new string[] { "id" }, DisplayName = "Parameter explicitly marked required: false is not required.")] [DataTestMethod] - public void ValidateRequestBodyContents(string entityName, string[] expectedParameters, string[] expectedParametersJsonTypes) + public void ValidateRequestBodyContents(string entityName, string[] expectedParameters, string[] expectedParametersJsonTypes, string[] expectedRequiredParameters) { Dictionary configuredOperations = ResolveConfiguredOperations(_runtimeEntities[entityName]); foreach (OperationType opType in configuredOperations.Keys) @@ -101,6 +149,13 @@ public void ValidateRequestBodyContents(string entityName, string[] expectedPara string expectedSchemaReferenceId = $"{entityName}{OpenApiDocumentor.SP_REQUEST_SUFFIX}"; ValidateOpenApiReferenceContents(schemaComponentReference, expectedSchemaReferenceId, expectedParameters, expectedParametersJsonTypes); + + // Validate that the expected parameters are marked as required in the schema component. + ISet requiredParameters = _openApiDocument.Components.Schemas[expectedSchemaReferenceId].Required ?? new HashSet(); + CollectionAssert.AreEquivalent( + expectedRequiredParameters, + requiredParameters.ToArray(), + message: "Unexpected required parameters in request body schema component."); } }