Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Optional stored procedure parameters generate the error "Missing required procedure parameters" #1748

Closed
1 task done
yorek opened this issue Sep 26, 2023 · 19 comments · Fixed by #2346
Closed
1 task done
Assignees
Labels
bug Something isn't working config changes related to config graphql rest stored-procedure
Milestone

Comments

@yorek
Copy link
Contributor

yorek commented Sep 26, 2023

What happened?

I have a stored procedure like the following:

create procedure dbo.stp_Dummy
@mandatoryParam int,
@optionalParam int = 10
as
select 
    @mandatoryParam as mandatoryParam,
    @optionalParam as optionalParam
go  

for which the @optionalParam is, as the name implies, optional.

If I configure DAB to use that stored procedure using the following configuration, omitting the optionalParam (since it is optional):

"Dummy": {
    "source": {
      "type": "stored-procedure",
      "object": "dbo.stp_Dummy",
      "parameters": {
        "mandatoryParam": 10
      }
    },
    "graphql": {
      "operation": "query"
    },
    "permissions": [
      {
        "role": "anonymous",
        "actions": [
          "execute"
        ]
      }
    ]
  }

I get the following error during the startup:

 Azure.DataApiBuilder.Service.Exceptions.DataApiBuilderException: Invalid request. Missing required procedure parameters: optionalParam for entity: Dummy

Version

Microsoft.DataApiBuilder 0.8.52+c69925060e1942d28515b9c4b89ea24832da0c7c

What database are you using?

Azure SQL

What hosting model are you using?

Local (including CLI)

Which API approach are you accessing DAB through?

REST, GraphQL

Relevant log output

Information: Microsoft.DataApiBuilder 0.8.52+c69925060e1942d28515b9c4b89ea24832da0c7c
Information: Config not provided. Trying to get default config based on DAB_ENVIRONMENT...
Information: Environment variable DAB_ENVIRONMENT is (null)
Loading config file from dab-config.json.
Information: Loaded config file: dab-config.json
Information: Setting default minimum LogLevel: Debug for Development mode.
Starting the runtime engine...
Loading config file from dab-config.json.
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[63]
      User profile is available. Using 'C:\Users\damauri\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
info: Azure.DataApiBuilder.Core.Services.ISqlMetadataProvider[0]
      Dummy path: /api/Dummy
dbug: Azure.DataApiBuilder.Core.Resolvers.IQueryExecutor[0]
      Executing query:
SELECT name as result_field_name, TYPE_NAME(system_type_id) as result_type, is_nullable FROM sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID('dbo.stp_Dummy'), 0) WHERE is_hidden is not NULL AND is_hidden = 0
dbug: Azure.DataApiBuilder.Core.Services.ISqlMetadataProvider[0]
      Logging primary key information for entity: Dummy.
info: Azure.DataApiBuilder.Core.Configurations.RuntimeConfigValidator[0]
      Validating Relationship Section in Config...
fail: Azure.DataApiBuilder.Service.Startup[0]
      Unable to complete runtime initialization. Refer to exception for error details.
      Azure.DataApiBuilder.Service.Exceptions.DataApiBuilderException: Invalid request. Missing required procedure parameters: optionalParam for entity: Dummy
         at Azure.DataApiBuilder.Core.Configurations.RuntimeConfigValidator.ValidateStoredProceduresInConfig(RuntimeConfig runtimeConfig, ISqlMetadataProvider sqlMetadataProvider)
         at Azure.DataApiBuilder.Service.Startup.PerformOnConfigChangeAsync(IApplicationBuilder app)
fail: Azure.DataApiBuilder.Service.Startup[0]
      Exiting the runtime engine...
crit: Microsoft.AspNetCore.Hosting.Diagnostics[6]
      Application startup exception
      System.ApplicationException: Could not initialize the engine with the runtime config file: dab-config.json
         at Azure.DataApiBuilder.Service.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env, RuntimeConfigProvider runtimeConfigProvider)
         at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
         at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
         at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
         at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
         at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)  
         at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
         at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)       
         at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Unable to launch the runtime due to: System.ApplicationException: Could not initialize the engine with the runtime config file: dab-config.json
   at Azure.DataApiBuilder.Service.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env, RuntimeConfigProvider runtimeConfigProvider)
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)        
   at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at Azure.DataApiBuilder.Service.Program.StartEngine(String[] args)
Error: Failed to start the engine.

Code of Conduct

  • I agree to follow this project's Code of Conduct
@yorek yorek added bug Something isn't working triage issues to be triaged labels Sep 26, 2023
@rohkhann
Copy link
Contributor

this is related to this: #989. There is a validation error that is done on the runtimeconfig where we check that number of params on stored proc should match number in runtimeconfig, which is incorrect. We had reported this during our sync ups. I have the fix for this and will check it in soon.

@rohkhann rohkhann self-assigned this Sep 26, 2023
@seantleonard
Copy link
Contributor

@rohkhann and @abhishekkumams can you check if #1847 does indeed resolve this issue too? if so, please link the pr item and close this.

@seantleonard seantleonard removed the triage issues to be triaged label Feb 8, 2024
@seantleonard
Copy link
Contributor

@rohkhann to confirm whether this is resolved.

@simonsabin
Copy link
Collaborator

We're hitting this issue

@seantleonard
Copy link
Contributor

@simonsabin, which version of DAB are you using?

@simonsabin
Copy link
Collaborator

simonsabin commented Mar 26, 2024 via email

@rohkhann
Copy link
Contributor

Now, if you have parameters in your stored proc, you dont need to duplicate those parameters on the config file. Thats what this fix handles: #1847. However, we still dont have the capability to detect an optional parameter if it is not specified in the call to the stored proc.

@simonsabin
Copy link
Collaborator

Thats a massive problem as there is no way to deploy the change without breaking the system. Which ever is deployed first, DAB or DB, the result is DAB fails to run until both are deployed

@seantleonard seantleonard added this to the 1.2rc milestone Apr 29, 2024
@seantleonard seantleonard added graphql rest config changes related to config labels May 17, 2024
@seantleonard seantleonard modified the milestones: 1.2rc, Feature Backlog May 17, 2024
@BenMenegazzo
Copy link

I have hit this issue today. What is a good work-around for optional parameters?

@Benjiiim
Copy link
Contributor

Benjiiim commented Jul 7, 2024

Hitting a similar issue as well, with a "Missing required procedure parameters" during a call to a stored proc with an optional parameter (not declared in the dab config file) without passing this parameter for this call.
Please see #2245

@simonsabin
Copy link
Collaborator

I believe this should be removed

throw new DataApiBuilderException(message: $"Did not provide all procedure params, missing: \"{paramKey}\"",
or some configuration to remove it.
Sure there is value at design time if the configuration hasn't been setup correctly to provide a nicer error, but you will still get an error if you don't specify all the required parameters.

@Benjiiim
Copy link
Contributor

Benjiiim commented Jul 8, 2024

On my end, this is the Exception I'm hitting when trying to call a stored procedure without providing a value for a parameter for which the stored procedure has a default value:

throw new DataApiBuilderException(
message: $"Invalid request. Missing required procedure parameters: {string.Join(", ", missingFields)}" +
$" for entity: {spRequestCtx.EntityName}",
statusCode: HttpStatusCode.BadRequest,
subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest);

@simonsabin
Copy link
Collaborator

That as well then. I'd do a PR but think this needs a discussion on whether its by default or configurable.

@Benjiiim
Copy link
Contributor

@seantleonard, @rohkhann, @abhishekkumams > may I ask you your thoughts on this one?

@seantleonard
Copy link
Contributor

@Benjiiim, agreed with your and @simonsabin's finding. Working on a fix that incorporate both of your experiences encountering errors.

There isn't a straightforward method to determine whether a stored procedure has a default valued parameter and what that value is without parsing the object definition which is error prone.

Instead, the change I'm making essentially defers error handling to the database. In this case, error 201:

"201", // Procedure or function '%.*ls' expects parameter '%.*ls', which was not supplied.

SELECT message_id AS Error,
    severity AS Severity,
    [Event Logged] = CASE is_event_logged
        WHEN 0 THEN 'No' ELSE 'Yes'
        END,
    [text] AS [Description]
FROM sys.messages
WHERE language_id = 1033 
and message_id = 201

Consequently, DAB will not fail startup or terminate a request when DAB doesn't detect an optional parameter in the request body when DAB runtime config doesn't define a default value for that optional parameter.

What do you think?

@simonsabin
Copy link
Collaborator

simonsabin commented Jul 25, 2024 via email

@seantleonard
Copy link
Contributor

seantleonard commented Jul 25, 2024

Hi Simon,

I have a working branch here: https://github.com/Azure/data-api-builder/tree/dev/sean/sp_opt_1748

I'd be happy to help you work on your suggestion:

I think there is a case that needs to be dealt with and that’s a parameter that’s defined in the config that’s not supplied and no default.

To clarify, when you say parameter defined in the config file, do you mean this? https://learn.microsoft.com/azure/data-api-builder/reference-configuration#parameters

{
  "entities": {
    "<entity-name>": {
      ...
      "type": "stored-procedure",
      "parameters": {
        "<parameter-name-1>" : "<default-value>",
        "<parameter-name-2>" : "<default-value>",
        "<parameter-name-3>" : "<default-value>"
      }
    }
  }
}

a value is required when defining params in the config. Perhaps you encountered a bug where an invalid, empty, or null value is provided for the parameter and DAB isn't handling properly?

@simonsabin
Copy link
Collaborator

It’s just about what gets validated where and what’s controllable and how.
Thinking about it, what is validating data types, default values.
I as was pointed out there were a number of places in the code base this touched and on my investigation some didn’t have test cases thus the desire to understand how we put tests in place for this stuffs

@seantleonard
Copy link
Contributor

I see. Do you have a few test cases in mind? That way I can better guide you were those can be added.

seantleonard added a commit that referenced this issue Sep 27, 2024
… procedure params are excluded from config (#2346)

## Why make this change?

- Closes #1748
- DAB should not crash during startup for the following scenario:
1. Database Stored procedure defined with 2 parameters (at least 1
mandatory param). DAB config defines default values for 1 of 2 of those
parameters. Consequently, DAB fails config validation because the number
of default parameters defined does not match the number of parameters in
the database. However, this is not an issue when 0 config param defaults
are defined. This leads to the next scenario:
2. DAB should not fail a request when config doesn't define default
values for parameters and database does. Should let database handle the
error because DAB has no way of resolving mandatory vs. optional stored
procedure parameters.

## What is this change?

1. Adds new sub-status code `DatabaseInputError` that is used when MSSQL
returns error code 201 with message:
> Procedure or function '%.*ls' expects parameter '%.*ls', which was not
supplied.
1. With this change, DAB **now returns** the following error to the
client when DAB config doesn't define default values for mandatory
stored procedure parameters:
    > Invalid request. Missing required request parameters.

1. The db returned error contains database object metadata which we have
typically avoided returning to the client from DAB engine because the
dab config file typically overrides any database object names. DAB will
return
1. `DabGraphQLResultSerializer` class added which ensures that responses
indicating 'missing procedure parameters' result in HTTP 400 for the
GraphQL endpoint. REST endpoint returns 400 without needing the result
serializer.

### Example requests
Use the sample db schema and dab config from the linked issue.
1. GraphQL Endpoint
```graphql
query ExecuteDummy {
    executeDummy {
        mandatoryParam
        optionalParam
    }
}
```
Response HTTP 400
```json
{
  "errors": [
    {
      "message": "Invalid request. Missing required request parameters.",
      "extensions": {
        "message": "Invalid request. Missing required request parameters.",
        "stackTrace": "<stack trace omitted for brevity>",
        "code": "DatabaseInputError"
      }
    }
  ]
}
```

3. REST endpoint
```https
GET localhost:5000/api/Dummy?optionalParam=2345
```

Response HTTP 400
```json
{
    "error": {
        "code": "DatabaseInputError",
        "message": "Invalid request. Missing required request parameters.",
        "status": 400
    }
}
```

## How was this tested?
updates stored procedure tests which check for missing required request
parameters.
- [x] Integration Tests
- [x] Unit Tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working config changes related to config graphql rest stored-procedure
Projects
None yet
6 participants