graphql-aspnet
graphql-aspnet copied to clipboard
I get a GraphTypeDeclarationException when using IGraphActionResult
MY CODE
using Application.DTO.Registry;
using Application.IServices;
using GraphQL.AspNet.Attributes;
using GraphQL.AspNet.Controllers;
using GraphQL.AspNet.Interfaces.Controllers;
using System.Threading.Tasks;
namespace GraphQL.Controllers.Auth
{
public class RegistryController : GraphController
{
private IRegistryService registryService;
public RegistryController(IRegistryService registryService)
{
this.registryService = registryService;
}
[MutationRoot("registry")]
public async Task<IGraphActionResult> Registry(RegistryRequest request)
{
await registryService.RegistryAsync(request);
return this.Ok();
}
}
}
ERROR
Unhandled exception. GraphQL.AspNet.Execution.Exceptions.GraphTypeDeclarationException: An error occured while trying to add a dependent of 'RegistryController' to the target schema. See inner exception for details.
---> GraphQL.AspNet.Execution.Exceptions.GraphTypeDeclarationException: The field 'GraphQL.Controllers.Auth.RegistryController.Registry' defines a a return type of object, which is cannot a be used as a graph type. Change the return type or skip the field and try again.
at GraphQL.AspNet.Internal.TypeTemplates.GraphFieldTemplateBase.ValidateOrThrow(Boolean validateChildren)
at GraphQL.AspNet.Internal.TypeTemplates.MethodGraphFieldTemplateBase.ValidateOrThrow(Boolean validateChildren)
at GraphQL.AspNet.Internal.TypeTemplates.ControllerActionGraphFieldTemplate.ValidateOrThrow(Boolean validateChildren)
at GraphQL.AspNet.Engine.TypeMakers.GraphFieldMaker.CreateField(IGraphFieldTemplate template)
at GraphQL.AspNet.Schemas.GraphSchemaManager.AddActionAsField(IObjectGraphType parentType, IGraphFieldTemplate action)
at GraphQL.AspNet.Schemas.GraphSchemaManager.AddAction(IGraphFieldTemplate action)
at GraphQL.AspNet.Schemas.GraphSchemaManager.AddController(IGraphControllerTemplate gcd)
at GraphQL.AspNet.Schemas.GraphSchemaManager.EnsureGraphTypeInternal(Type type, Nullable`1 kind)
at GraphQL.AspNet.Schemas.GraphSchemaManager.EnsureGraphType(Type type, Nullable`1 kind)
--- End of inner exception stack trace ---
at GraphQL.AspNet.Schemas.GraphSchemaManager.EnsureGraphType(Type type, Nullable`1 kind)
at GraphQL.AspNet.Execution.GraphSchemaInitializer`1.Initialize(TSchema schema)
at GraphQL.AspNet.Configuration.Startup.GraphQLSchemaInjector`1.BuildNewSchemaInstance(IServiceProvider serviceProvider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at GraphQL.AspNet.Configuration.Startup.GraphQLSchemaInjector`1.UseSchema(IServiceProvider serviceProvider, Boolean invokeServerExtensions)
at GraphQL.AspNet.Configuration.Startup.GraphQLSchemaInjector`1.UseSchema(IApplicationBuilder appBuilder)
at GraphQL.AspNet.Configuration.GraphQLSchemaBuilderExtensions.UseGraphQL(IApplicationBuilder app)
at GraphQL.Program.Main(String[] args) in E:\CodeProjects\C#\ASP.NET\BookLib\src\Presentation\GraphQL\Program.cs:line 49
E:\CodeProjects\C#\ASP.NET\BookLib\src\Presentation\GraphQL\bin\Release\net7.0\GraphQL.exe (process 19892) exited with code -532462766.
Press any key to close this window . . .
Hey @HallisCode thanks for reaching out!
GraphQL is strongly typed, it has to know what the expected return type of any field is going to be at compile time. This is different than a REST call where whatever you return, even if its nothing, can just be interpreted in the moment and serialized out.
That means for any controller action method (which is ultimately a proxy for a field) the runtime has to know what specific type you intend to return from it. As written your method doesn't define a concrete return type, just an action result. This means the library defaults to the most generic of possible return types, object
, which is not allowed so it errors out.
A couple options should get you on your way:
1. Declare an explicit return type
One option is to return an exact type or interface from your field:
[MutationRoot("registry")]
public async Task<MyCustomObjectType> Registry(RegistryRequest request)
{
await registryService.RegistryAsync(request);
MyCustomObjectType item = /* create an object here*/
return item;
}
2. Provide a type hint
If you want to make use of the additional metadata and processing help of IGraphActionResult
then you need to provide the compiler a hint at what object you intend to return when everything runs correctly. This can be done in the [MutationRoot]
attribute
[MutationRoot("registry", typeof(MyCustomObjectType))]
public async Task<IGraphActionResult> Registry(RegistryRequest request)
{
await registryService.RegistryAsync(request);
MyCustomObjectType item = /* create an object here*/
return this.Ok(item);
}
You're more than welcome to return null
as well (which is what this.Ok()
does) if it makes sense for your target return type. But the intended schema must be known at startup.
Hope this helps, Kevin