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

Support for property resolvers for interface types #429

Closed
justinmchase opened this issue Oct 1, 2019 · 8 comments
Closed

Support for property resolvers for interface types #429

justinmchase opened this issue Oct 1, 2019 · 8 comments

Comments

@justinmchase
Copy link

I'm submitting a...

[x] Feature request

Current behavior

I would like to create a resolver for an interface type which has a property resolver

Expected behavior

I should be able to define a resolver for an interface type and add property resolvers for virtual fields on that resolver. It should have access to services via constructor injection, etc.

Minimal reproduction of the problem with instructions

@InterfaceType()
export class IExample {
}

@Resolver(of => IExample)
export class ExampleResolver {
  constructor(
    private readonly example: ExampleService
  ) { }

  @ResolveProperty(type => Boolean)
  public async foo(@Root() item: IExample) {
    // this.example is available for this function
    return false
  }
}

What is the motivation / use case for changing the behavior?

If you have an interface type with multiple concrete types you want to be able to access it in gql like:

examples {
  foo
}

Not

examples {
  ... on ConcreteType {
    foo
  }
}

Which it seems like right now the only way to do it is to promote the field to resolvers for each concrete type.

Environment

Nest version: ^6.7.2
For Tooling issues:

  • Node version: v12.8.0
  • Platform: linux
@justinmchase
Copy link
Author

By the way the error I get when I try to do this is:

{
  "code": "GRAPHQL_VALIDATION_FAILED",
  "exception": {
    "stacktrace": [
      "GraphQLError: Cannot query field \"foo\" on type \"IExample\". Did you mean to use an inline fragment on \"ConcreteType\"?",
      "..."
    ]
  }
}

@marcus-sa
Copy link
Contributor

marcus-sa commented Oct 4, 2019

You can't query interfaces, you can only implement them.

EDIT:
It seems like I've misunderstood your question.
This is out of the scope (as it's not supported in the GraphQL spec)

@kamilmysliwiec
Copy link
Member

It's not related to NestJS, but rather the GraphQL itself

@justinmchase
Copy link
Author

I think you can, it clearly works for fields right on the object. I think that my problem may simply be that I didn't put the field on the interface though! I'll double check and follow up here.

Thanks.

@marcus-sa
Copy link
Contributor

marcus-sa commented Oct 4, 2019

@justinmchase nope you can't.
An interface in GraphQL is just like an interface in TS.
You need to implement a type with it before you can query it.
https://graphql.org/learn/schema/#interfaces

@justinmchase
Copy link
Author

Well they're doing it even in that example you linked...

The character interface has a name field which you can then query without the concrete type. Of course the object you're returning has to match a concrete type in the union but you should be able to query fields on the interface type without having to use a concrete fragment.

interface Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name # <-- this is a field on the interface
    ... on Droid {
      primaryFunction
    }
  }
}

Imagine you want the name field to be a resolver which is the same for all implementers of Character. I'll play with it a little later, I think I forgot to put the field on my interface and that's whats really blocking me.

@justinmchase
Copy link
Author

justinmchase commented Oct 5, 2019

Looking at this more, adding the field to the interface doesn't help. I am getting a crash in type-graphql which I'm filing a bug over there for but I do think that this is a legitimate issue in this library and think this ticket should be re-opened.

I think its legitimate because I am able to do this with graphql without using this library and it is documented in their documentation and it is a limitation of this library that this isn't supported.

I think the example from the gql documentation for characters that @marcus-sa linked to is a good one, so this feature request / bug becomes how can I implement Character.name as a property resolver?

@InterfaceType()
export class Character {
  @Field()
   public name: string
}

@Resolver(of => Character ) // <-- this crashes my app
export class CharacterResolver {
  constructor(
    private readonly characters: CharacterService
  ) { }

  @ResolveProperty(type => String)
  public async name(@Root() character: Character) {
    return this.charcters.resolveName(character)
  }
}

@lock
Copy link

lock bot commented Apr 25, 2020

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Apr 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants