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

union/interface type resolution not working/missing #15

Closed
fosk06 opened this issue Apr 8, 2018 · 15 comments
Closed

union/interface type resolution not working/missing #15

fosk06 opened this issue Apr 8, 2018 · 15 comments
Labels

Comments

@fosk06
Copy link

fosk06 commented Apr 8, 2018

I'm submitting a...Bug report


[ ] Regression 
[*] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
 

Current behavior

Hello,
I'm using the graphql example( in the example directory of nest) with the Cat CRUD and i try to use a union type and interface but i didn't find a way to do it.
When i try to request my data with a fragment, i have the following error :

"Abstract type MutationResult must resolve to an Object type at runtime for field Mutation.createCat with value "[object Object]", received "undefined". Either the MutationResult type should provide a "resolveType" function or each possible types should provide an "isTypeOf" function."

There is nothing in the doc explaining how to use union / interface, and there is nothing in the graphql example.

In the apollo documentation, the type resolver ( here "Cat" Resolver") should implement a __resolveType function. I tried to set this function in the @resolver('Cat') class CatsResolvers
but it's not working.

I tried to add it on the cat resolvers class

Expected behavior

The request should return either a Cat item or GraphQLErrorItem from my schema definition.

Minimal reproduction of the problem with instructions


export interface GraphQLError {
    readonly message: string;
    readonly errorCode: number;
    readonly type: string;
}
 
  • add type and union

type GraphQLError {
    message: String
    errorCode: Int
    type: String
}
union MutationResult = Cat | GraphQLError
 
  • change the createCat Mutation in the schema

- createCat(name: String, age: Int): MutationResult
 
  • add the function in cats.resolvers.ts in the CatsResolvers class

__resolveType(obj, context, info): string{
    return obj.errorCode ? 'GraphQLError' : 'Cat';
  }
 

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

Environment


Nest version: 4.5.10 (core)

 
For Tooling issues:
- Node version: 9.4
- Platform:  Mac

Others:

 
@cschroeter
Copy link

cschroeter commented Apr 23, 2018

@fosk06 For error handling you are not required to do something like unions. In your app.module or graphql.module you can simply just do this

      .apply(
        graphqlExpress(async req => ({
          schema: schema
          rootValue: req,
          context: req,
          formatError: (error: GraphQLError) => {
            return error.originalError instanceof BaseException ? error.originalError.serialize() : error;
          }
        }))
      )

@kamilmysliwiec But for real unions and interfaces it is not quite clear how to resolve those.

# Schema
union SearchResult = Human | Droid | Starship

# Query
{
  search(text: "an") {
    ... on Human {
      name
      height
    }
    ... on Droid {
      name
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}

A NestJS way could look somethin like

 @ResolveType('SearchResult')
  async resolveType(obj) {
    if(obj.height){
      return 'Human';
    }

    if(obj.length){
      return 'Starship';
    }
  }

What do you think?

@triedal
Copy link

triedal commented May 1, 2018

This is something I am struggling with as well.

@ph55
Copy link

ph55 commented May 16, 2018

Same here.

There is workaround though - add it manually when creating schema (ugly one)

    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphqls');

    const resolvers = {
      LoginResponse: {
        __resolveType(obj, context, info) {
          if (obj.error) {
            return 'LoginFailure';
          }

          return 'LoginSuccess';
        }
      }
    };

    const schema = this.graphQLFactory.createSchema({ typeDefs, resolvers });

@obedm503
Copy link

you can do this by defining it as a normal type

@Resolver('LoginResponse')
export class LoginResponseResolver {
  @ResolveProperty('__resolveType')
  __resolveType(obj) {
    if (obj.error) {
      return 'LoginFailure';
   }
   return 'LoginSuccess';
  }
}

@ph55
Copy link

ph55 commented May 16, 2018

Yay, thanks

@kamilmysliwiec
Copy link
Member

Actually, this should be enough (you can omit __resolveType inside parenthesis):

@Resolver('LoginResponse')
export class LoginResponseResolver {
  @ResolveProperty()
  __resolveType(obj) {
    if (obj.error) {
      return 'LoginFailure';
   }
   return 'LoginSuccess';
  }
}

@igat64
Copy link

igat64 commented Jul 10, 2018

Hey guys @kamilmysliwiec @ph55 @obedm503

I faced a similar problem but a bit different:

Let's say we have the following schema:

type Component {
  id: ID!
  type: ComponentTypes!
  order: Int!
  properties: ComponentProps!
}

enum ComponentTypes {
  TEXT
  BUTTON
}

union ComponentProps = TextComponentProps | ButtonComponentProps

type TextComponentProps {
  text: String
}
type ButtonComponentProps {
  color: String
}

How to resolve union ComponentProps as it depend on Component.type value?

@jurStv
Copy link

jurStv commented Jul 11, 2018

Hey @kamilmysliwiec @ph55 @obedm503
Can you help with some advice on this ⬆️ please

@dkushner
Copy link

Still unclear on how this is meant to work. @kamilmysliwiec, would you mind clarifying this use case? I have a resolver the way you have specified and yet still receive the warning.

@obedm503
Copy link

@igat64 it's not possible since TextComponentProps or ButtonComponentProps doesn't have a way to relate back to the component type. the code would just have to know the relationships

@igat64
Copy link

igat64 commented Dec 22, 2018

Thank you for the answer @obedm503

@yassernasc
Copy link

Hey, great solution but i think it could be better, just using a ResolveProperty function instead using a Resolver, because it needs the creation a new class and file for each union type, it creates multiples scopes of one model that should be summed up in one general resolver file. What do you guys think about it?

@coderdiaz
Copy link

@yasserN What is your solution proposal?

@chnirt
Copy link

chnirt commented Sep 6, 2019

Anyone help me to demo union with nestjs + graphql ?

@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
Projects
None yet
Development

No branches or pull requests