0
votes

It seems like I'm not getting something fundamental with graphql.

I am trying to get a user by it's id which is in turn the result of another query. In this case a query on some session data.

I don't understand why the error occurs.

Here's my code:

{
    session(key: "558fd6c627267d737d11e758f1ae48cae71fc9b584e2882926ad5470c88d7c3ace08c9c7") {
        userId
        expires
        user(id: userId) {
            name
        }
    }
}

And I get

Unknown argument "id" on field "user" of type "Session"

My schema looks like this:

type Session {
    userId: String,
    expires: String,
    user: User
}

type User {
    _id: String
    name: String
    email: String
    firstName: String
    lastName: String
}

type Query {
    session(key: String!): Session
    user(id: String!): User
}

Addendum Feb 23 2017

I apologize that I wasn't sufficiently explicit about the corresponding resolvers in my initial post. Yes, I my resolvers are defined and e. g. the query works for session if I don't add users.

Here's my root:

{
    Query: {
        async user(parentValue, args, req) {
            let user = await adapters.users.byId(args.id);
            return user;
        },
        async session(parentValue, args, req) {
            let session = await adapters.session(args.key);
            let userId = session.session.userId;
            let expires = session.expires;
            return {userId: userId, expires: expires};
        }
    }

}
1

1 Answers

0
votes

You need to create some resolver function on field user in type Session, because GraphQL does not know how to return the user. In graphql-js it would look like that

const Session = new GraphQLObjectType({
    name: 'Session',
    fields: {
        userId: { type: GraphQLString },
        expires: { type: GraphQLString },
        user: {
            type: User, // it is your GraphQL type
            resolve: function(obj, args, context){
                // obj is the session object returned by ID specified in the query
                // it contains attributes userId and expires
                // however graphql does not know you want to use the userId in order to retrieve user of this session
                // that is why you need to specify the value for field user in type Session
                return db.User.findById(obj.userId).then(function(user){
                    return user;
                });
            }
        }
    }
});

It is just a simple example from Node.js to show you how you could return the user instance. You have the possibility of specifying how to retrieve values of every field in each GraphQL type (each field can have it's own resolve function).

I suggest you read the GraphQL documentation concerning root and resolvers

EDIT

I will show you an example how you can deal with such a situation. Let's consider two types: User and Session

type User {
    _id: String
    name: String
}

type Session {
    expires: String
    user: User
}

If you want your query to return Session object together with it's User, you do not need to include the userId field in Session type. You can solve this situation in two ways. First one is to use single resolver for the session query.

{
    Query: {
        async session(parentValue, args, req) {
            let session = await adapters.session(args.key);
            // now you have your session object with expires and userId attributes
            // in order to return session with user from query, you can simply retrieve user with userId
            let user = await adapter.users.byId(session.userId);
            return { expires: session.expires, user: user }
        }
    }
}

This is your first option. With that solution you can return session object with user assigned to it via single query and without extra resolve methods on any fields of Session type. The second solution is the one I have shown previously, where you use resolve method on field user of Session type - so you simply tell GraphQL how it should obtain the value for this field.