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
947 stars 196 forks source link

[Bug]: The graphql endpoint returns a 500 statuscode when you define a graphql union type #1384

Open dgcaron opened 1 year ago

dgcaron commented 1 year ago

What happened?

I have setup a graphql endpoint using cosmos db and have defined a union type like described here https://graphql.org/learn/schema/#union-types. when i call the graphql endpoint it returns an 500 status code

Version

0.5.35

What database are you using?

CosmosDB NoSQL

What hosting model are you using?

Static Web Apps (SWA)

Which API approach are you accessing DAB through?

GraphQL

Relevant log output

[dataApi]       Connection id "0HMPGUO3GKV4E", Request id "0HMPGUO3GKV4E:00000002": An unhandled exception was thrown by the application.
[dataApi]       HotChocolate.SchemaException: For more details look at the `Errors` property.
[dataApi]
[dataApi]       1. Unable to resolve type reference `None: SettingsDataOrderByInput`. (HotChocolate.Types.InputObjectType)
[dataApi]
[dataApi]          at HotChocolate.Configuration.RegisteredType.GetType[T](ITypeReference typeRef)
[dataApi]          at HotChocolate.Types.InputField.OnCompleteField(ITypeCompletionContext context, ITypeSystemMember declaringMember, InputFieldDefinition definition)
[dataApi]          at HotChocolate.Types.FieldBase`1.CompleteField(ITypeCompletionContext context, ITypeSystemMember declaringMember)
[dataApi]          at HotChocolate.Types.FieldBase`1.HotChocolate.Types.Helpers.IFieldCompletion.CompleteField(ITypeCompletionContext context, ITypeSystemMember declaringMember)
[dataApi]          at HotChocolate.Internal.FieldInitHelper.CompleteFieldsInternal[TField](ITypeCompletionContext context, ITypeSystemMember declaringMember, TField[] fields)
[dataApi]          at HotChocolate.Internal.FieldInitHelper.CompleteFieldsInternal[TFieldDefinition,TField](ITypeCompletionContext context, ITypeSystemMember declaringMember, IEnumerable`1 fieldDefinitions, Func`3 fieldFactory, Int32 fieldCount)   
[dataApi]          at HotChocolate.Internal.FieldInitHelper.CompleteFields[TFieldDefinition,TField](ITypeCompletionContext context, ITypeSystemMember declaringMember, IReadOnlyList`1 fieldDefs, Func`3 fieldFactory)
[dataApi]          at HotChocolate.Types.InputObjectType.OnCompleteFields(ITypeCompletionContext context, InputObjectTypeDefinition definition)
[dataApi]          at HotChocolate.Types.InputObjectType.OnCompleteType(ITypeCompletionContext context, InputObjectTypeDefinition definition)
[dataApi]          at HotChocolate.Types.TypeSystemObjectBase`1.CompleteType(ITypeCompletionContext context)
[dataApi]          at HotChocolate.Configuration.TypeInitializer.<CompleteTypes>g__CompleteType|27_0(RegisteredType registeredType)
[dataApi]          at HotChocolate.Configuration.TypeInitializer.ProcessTypes(TypeDependencyKind kind, Func`2 action)
[dataApi]          at HotChocolate.Configuration.TypeInitializer.CompleteTypes()
[dataApi]          at HotChocolate.Configuration.TypeInitializer.Initialize()
[dataApi]          at HotChocolate.SchemaBuilder.Setup.InitializeTypes(SchemaBuilder builder, IDescriptorContext context, IReadOnlyList`1 types, LazySchema lazySchema)
[dataApi]          at HotChocolate.SchemaBuilder.Setup.Create(SchemaBuilder builder, LazySchema lazySchema, IDescriptorContext context)
[dataApi]          at HotChocolate.SchemaBuilder.Create(IDescriptorContext context)
[dataApi]          at HotChocolate.SchemaBuilder.HotChocolate.ISchemaBuilder.Create(IDescriptorContext context)
[dataApi]          at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaAsync(NameString schemaName, RequestExecutorSetup options, RequestExecutorOptions executorOptions, IServiceProvider serviceProvider, TypeModuleChangeMonitor typeModuleChangeMonitor, CancellationToken cancellationToken)
[dataApi]          at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaServicesAsync(NameString schemaName, RequestExecutorSetup options, CancellationToken cancellationToken)
[dataApi]          at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorNoLockAsync(NameString schemaName, CancellationToken cancellationToken)
[dataApi]          at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorAsync(NameString schemaName, CancellationToken cancellationToken)
[dataApi]          at HotChocolate.Execution.RequestExecutorProxy.GetRequestExecutorAsync(CancellationToken cancellationToken)
[dataApi]          at HotChocolate.AspNetCore.HttpPostMiddlewareBase.HandleRequestAsync(HttpContext context, AllowedContentType contentType)
[dataApi]          at HotChocolate.AspNetCore.HttpPostMiddlewareBase.InvokeAsync(HttpContext context)
[dataApi]          at Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.<>c__DisplayClass13_0.<<UseCancellation>b__1>d.MoveNext()
[dataApi]       --- End of stack trace from previous location ---
[dataApi]          at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
[dataApi]          at Azure.DataApiBuilder.Service.Authorization.ClientRoleHeaderAuthorizationMiddleware.Invoke(HttpContext httpContext)
[dataApi]          at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
[dataApi]          at Azure.DataApiBuilder.Service.AuthenticationHelpers.ClientRoleHeaderAuthenticationMiddleware.InvokeAsync(HttpContext httpContext)
[dataApi]          at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
[dataApi]          at Azure.DataApiBuilder.Service.Startup.<>c__DisplayClass11_0.<<Configure>b__2>d.MoveNext()
[dataApi]       --- End of stack trace from previous location ---
[dataApi]          at Azure.DataApiBuilder.Service.Services.PathRewriteMiddleware.InvokeAsync(HttpContext httpContext)
[dataApi]          at Azure.DataApiBuilder.Service.Services.CorrelationIdMiddleware.Invoke(HttpContext httpContext)
[dataApi]          at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Code of Conduct

dgcaron commented 1 year ago

ok, manually defining the missing input types works om a sense that the api now returns rows and expects the correct partials.

in my case this was


type Setting @model {
  id: ID
  data: SettingsData
}

union SettingsData = Type1 | Type2 | Type3

input SettingsDataOrderByInput {
  type: String
}

input SettingsDataFilterInput {
  type: String
}

however, the data object remains empty. is there any guidance on how to set this up correctly?

sajeetharan commented 1 year ago

@dgcaron Thanks for reporting the issue, we will check and get back on this! If possible can you provide a sample document?

dgcaron commented 1 year ago

you mean a database configuration? this would represent my current setup. As a workaround i tried to add a policy to filter items in advance but that doesn't seem to be supported for cosmosdb (as it has no effect)

{
  "$schema": "https://dataapibuilder.azureedge.net/schemas/v0.5.34/dab.draft.schema.json",
  "data-source": {
    "database-type": "cosmosdb_nosql",
    "options": {
      "database": "...",
      "schema": "staticwebapp.database.schema.gql"
    },
    "connection-string": "..."
  },
  "runtime": {
    "graphql": {
      "allow-introspection": true,
      "enabled": true,
      "path": "/graphql"
    },
    "host": {
      "mode": "production",
      "cors": {
        "origins": [],
        "allow-credentials": false
      },
      "authentication": {
        "provider": "StaticWebApps"
      }
    }
  },
  "entities": {
    "Settings": {
      "source": "settings",
      "permissions": [
        {
          "actions": [
            {
              "action": "read"
            }
          ],
          "role": "anonymous"
        }
      ]
    }
  }
}

and

type Settings @model {
  id: ID
  type: string
  data: SettingsData
}

union SettingsData = Type1 | Type2 

type Type1 {
  prop1: string 
}

type Type1 {
  prop2: string
}

input SettingsDataOrderByInput {
  type: String
}

input SettingsDataFilterInput {
  type: String
}

and example document would be

{
"id": "<some random guid>",
"type": "Type1",
"data": {
  "prop1": "test"
  }
}
aaronpowell commented 1 year ago

I would say the bug is most likely within https://github.com/Azure/data-api-builder/blob/main/src/Service.GraphQLBuilder/Queries/InputTypeBuilder.cs#L112 and we're not handling the union type properly as it didn't generate the input type and then it also didn't generate the property correctly on the model.

dgcaron commented 8 months ago

Hi, just checking if there is any movement on this issue?