Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1a8edbe
Initial plan
Copilot Jun 26, 2026
4467e79
Mark stored procedure params without defaults as required in OpenAPI
Copilot Jun 26, 2026
d6bef3b
Add tests for SP parameter required logic in OpenAPI schema
Copilot Jul 7, 2026
3f4b30c
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 7, 2026
9f797d5
Potential fix for pull request finding
souvikghosh04 Jul 9, 2026
8154a7a
Update src/Service.Tests/OpenApiDocumentor/StoredProcedureGeneration.cs
souvikghosh04 Jul 9, 2026
e68102a
Fix IsRequestBodyRequired stored-procedure branch to honor Required=f…
Copilot Jul 9, 2026
6398a93
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 10, 2026
ac1774b
Fix whitespace formatting in StoredProcedureGeneration.cs
Copilot Jul 10, 2026
d614c62
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 15, 2026
3d38fb4
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 16, 2026
ad554cd
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 27, 2026
2d432dc
Fix GET SP query params required field; add requestBody.Required asse…
Copilot Jul 29, 2026
b8ea826
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 29, 2026
bf073c4
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 30, 2026
7c0b8a9
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Jul 30, 2026
224983a
Merge branch 'main' into copilot/fix-openapi-required-params
aaronburtle Jul 30, 2026
492409f
Merge branch 'main' into copilot/fix-openapi-required-params
aaronburtle Jul 30, 2026
e101a49
Reword SP GET query param required-flag doc comment for clarity
souvikghosh04 Aug 3, 2026
c4c4f58
Merge branch 'main' into copilot/fix-openapi-required-params
souvikghosh04 Aug 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/Core/Services/OpenAPI/OpenApiDocumentor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,9 +1135,9 @@ private static bool IsRequestBodyRequired(SourceDefinition sourceDef, bool consi
StoredProcedureDefinition spDef = (StoredProcedureDefinition)sourceDef;
foreach (KeyValuePair<string, ParameterDefinition> 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;
Expand Down Expand Up @@ -1422,7 +1422,10 @@ private static OpenApiSchema CreateSpRequestComponentSchema(Dictionary<string, P
Default = def.Default is not null ? new OpenApiString(def.Default) : null
});

if (def.Required == true)
// A parameter is required when it is explicitly marked required in the runtime config,
// or when no default value is available, in which case a value must be provided in the
// request body. This mirrors the logic used by IsRequestBodyRequired.
if (def.Required ?? !def.HasConfigDefault)
{
Comment thread
souvikghosh04 marked this conversation as resolved.
required.Add(parameter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,51 @@ public static void CreateEntities()
Relationships: null,
Description: "Represents a stored procedure for books");

// Entity whose "title" parameter has a config-provided default value.
// Because a default is available, "title" must not be flagged as required, while
// "publisher_id" (no default) must remain required.
Entity entity2 = new(
Source: new(
Object: "insert_book",
EntitySourceType.StoredProcedure,
Parameters: new List<ParameterMetadata>
{
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<ParameterMetadata>
{
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<string, Entity> entities = new()
{
{ "sp1", entity1 }
{ "sp1", entity1 },
{ "sp2", entity2 },
{ "sp3", entity3 }
};

_runtimeEntities = new(entities);
Expand All @@ -74,13 +116,19 @@ public static void CreateEntities()
/// <summary>
/// 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.
/// </summary>
/// <param name="entityName">Entity name</param>
/// <param name="expectedParameters">Expected parameters in request body</param>
/// <param name="expectedParametersJsonTypes">Expected parameter value types in request body.</param>
[DataRow("sp1", new string[] { "title", "publisher_name" }, new string[] { "string", "string" }, DisplayName = "Validate request body parameters and parameter Json data types.")]
/// <param name="expectedRequiredParameters">Expected parameters flagged as required in the schema component.</param>
[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<OperationType, bool> configuredOperations = ResolveConfiguredOperations(_runtimeEntities[entityName]);
foreach (OperationType opType in configuredOperations.Keys)
Expand All @@ -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<string> requiredParameters = _openApiDocument.Components.Schemas[expectedSchemaReferenceId].Required ?? new HashSet<string>();
CollectionAssert.AreEquivalent(
expectedRequiredParameters,
requiredParameters.ToArray(),
message: "Unexpected required parameters in request body schema component.");
}
Comment thread
souvikghosh04 marked this conversation as resolved.
}

Expand Down