Azure / data-api-builder

Data API builder provides modern REST and GraphQL endpoints to your Azure Databases and on-prem stores.
https://aka.ms/dab/docs
MIT License
889 stars 180 forks source link

[Bug]: GraphQL pagination attempts to return hasNextPage = null and fails with "Cannot return null for non-nullable field" #2281

Closed TzDeligoVision closed 3 weeks ago

TzDeligoVision commented 3 months ago

What happened?

We attempt to query data from an Azure SQL database table with the GraphQL interface page-by-page. For the repro we simplified the query to only fetch the primary key ThingID (PK, int, not null) and the Created (datetime2(7), null) fields and removed all filters.

query GetAllThings {
  things(
    first: 100,
    after: null,
  ) {
    items {
      ThingID
      Created
    }
    hasNextPage
    endCursor
  }
}

We get the following error response with HTTP status 200:

{
    "errors": [
        {
            "message": "Cannot return null for non-nullable field.",
            "locations": [
                {
                    "line": 10,
                    "column": 5
                }
            ],
            "path": [
                "things",
                "hasNextPage"
            ],
            "extensions": {
                "code": "HC0018"
            }
        }
    ],
    "data": {}
}

This error result is reproducible as long as we don't change the query above.

However, the result is seemingly unpredictable if we change the number of items requested:

Additional observations/cases:

What might be the root cause of this behaviour? Is it a reliable workaround/fix if we move the paging fields "up" before the items in our queries?

Version

1.1.7

What database are you using?

Azure SQL

What hosting model are you using?

Local (including CLI)

Which API approach are you accessing DAB through?

GraphQL

Relevant log output

dbug: Azure.DataApiBuilder.Core.Resolvers.IQueryExecutor[0]
      e2efd26f-c7ba-40d0-a626-d293fd3366a7 Executing query: SELECT TOP 101 [table0].[Created] AS [Created], [table0].[ThingID] AS [ThingID] FROM [dbo].[Thing] AS [table0] WHERE 1 = 1 ORDER BY [table0].[ThingID] ASC FOR JSON PATH, INCLUDE_NULL_VALUES
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'Hot Chocolate GraphQL Pipeline'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 POST http://localhost:5000/graphql - 200 - application/json;+charset=utf-8 217.6527ms

Code of Conduct

TzDeligoVision commented 3 months ago

There is another possible workaround to get back the "data" despite the invalid hasNextPage=null value, if I force the hasNextPage to be optional with a question mark:

query GetAllThings {
  things(
    first: 100,
    after: null,
  ) {
    items {
      Created
    }
    hasNextPage?
    endCursor
  }
}

This way we can at least get back the data, however, it is unclear how to "treat" the hasNextPage = null in our data processing.

{
    "data": {
        "things": {
            "items": [
                {
                    "ThingID": xyz,
                    "Created": "2024-06-27T09:37:51.019Z"
                },
                ...
            ],
            "hasNextPage": null,
            "endCursor": "...somecursorInBase64..."
        }
    }
}
aaronburtle commented 3 months ago

I've reproed this error, continuing investigation

image

image

abhishekkumams commented 2 months ago

I don't think it's related to datetime2_types field, since I was able to repro the error without using this field. image image