Unable to return an interface or a union type from a field in the schema

385 Views Asked by At

I was reading the graphQL doc and I found an issue while working with Inline Fragments and Interfaces

They mention in the document that we can also return an interface or union type in the schema, but GraphiQL returns the following error.

"Abstract type "User" must resolve to an Object type at runtime for field "Query.user". Either the "User" type should provide a "resolveType" function or each possible type should provide an "isTypeOf" function."

index.js

import express from "express";
import { graphqlHTTP } from "express-graphql";
import { buildSchema } from "graphql";

const UserStatuses = Object.freeze({
    "registered": "REGISTERED",
    "active": "ACTIVE",
    "inactive": "INACTIVE"
});
const users = [
    {
        "id": 120,
        "first_name": "Admin",
        "last_name": "Kumar",
        "email": "[email protected]",
        "dob": "1980-01-01",
        "age": 42,
        "is_admin": true,
        "status": UserStatuses['active']
    },
    {
        "id": 121,
        "first_name": "Sachin",
        "last_name": "Kumar",
        "email": "[email protected]",
        "dob": "1994-01-01",
        "age": 28,
        "status": UserStatuses['active'],
        "tasks": []
    },
    {
        "id": 122,
        "first_name": "Sumit",
        "last_name": "Kumar",
        "email": "[email protected]",
        "dob": "1992-01-01",
        "age": 30,
        "status": UserStatuses['active'],
        "tasks": []
    },
    {
        "id": 123,
        "first_name": "Akash",
        "last_name": "Kumar",
        "email": "[email protected]",
        "dob": "1993-01-01",
        "age": 29,
        "status": UserStatuses['inactive'],
        "tasks": []
    },
    {
        "id": 124,
        "first_name": "Ravi",
        "last_name": "Kumar",
        "email": "[email protected]",
        "dob": "1991-01-01",
        "age": 31,
        "status": UserStatuses['registered'],
        "tasks": []
    }
];

var schema = buildSchema(`
    type Query {
        user(id: Int): User
    }
    interface User {
        id: ID!
        first_name: String!
        last_name: String!
        email: String!
    }
    enum UserStatus {
        REGISTERED
        ACTIVE
        INACTIVE
    }

    type AppUser implements User {
        id: ID!
        first_name: String!
        last_name: String!
        email: String!
    
        age: Int!
        status: UserStatus!
    }
    type AdminUser implements User {
        id: ID!
        first_name: String!
        last_name: String!
        email: String!
    
        is_admin: Boolean
        status: UserStatus!
    }
`);

var root = {
    user: function ({id}) {
        let user = users.find(u => u.id == id);
        return user;
    },
}

var app = express();

// for testing purposes.
app.get('/', (req, res) => {
    return res.send("Hello World!");
});

app.use('/graphql', graphqlHTTP({
    schema,
    rootValue: root,
    pretty: true,
    graphiql: true
}))

app.listen(4000, () => console.log('Graphql Server is browse to http://localhost:4000/graphql'));

the query that I want to execute on GraphiQL

query general{
    user(id: 120) {
        id
        first_name
        __typename
    }
}
1

There are 1 best solutions below

2
On

You should be able to add a __resolveType field to your user object to disambiguate.

var root = {
    user: function ({id}) {
        let user = users.find(u => u.id === id);
        user['__resolveType'] = user.is_admin ? 'AdminUser' : 'AppUser';
        return user;
    },
}