简体   繁体   中英

In GraphQL, how do I implement optional queries?

EDIT: Since it doesn't seem to be clear, I am specifically asking about the DB requests I should be making inside the resolve function for a query on the backend.

I am implementing GraphQL queries, and I am having trouble understanding exactly how many calls I should make in a given query. For example, here's a data structure with users and clubs that the user can join:

User {
  UserID
  Clubs
  OtherStuff
}

Club{
  ClubID
  ClubName
}

I have the following calls I can make to my DB:

  • Get all UserIDs
  • Get info for UserID
  • Get all ClubIDs for a user
  • Get info for ClubID

The thing I don't understand is whether I should be making all of these calls every time Users is queried. If someone is only querying UserIDs, it seems like a huge waste to retrieve everything else. Should Clubs for User be a totally separate GraphQL query, should Clubs only return ClubIDs, or is there a way to efficiently allow full Club info to be available in the Clubs field?

EDIT 2: Ok so here's my code. I've commented the part where I'm not sure what to do.

const QueryType = new GraphQLObjectType({
  name: 'Query',
  fields: {
    User: userQueryField,
    Club: clubQueryField
  }
});

const clubQueryField = {
  type: new GraphQLList(ClubType),
  args: {
    UserID: {
      description: 'Returns all clubs the user is a part of',
      type: GraphQLID
    }
  },
  resolve(root, {UserID}) {
    //.....
  }
};


const userQueryField = {
  type: new GraphQLList(UserType),
  args: {
    UserID: {
      description: 'If omitted, returns a list of all users. \
      Otherwise, returns the user with the provided ID',
      type: GraphQLID
    }
  },
  resolve(root, {UserID}) {
    if(UserID){
      return new Promise((resolve, reject) => {
        getUserInfo(UserID, function(response){

          //HERE: I have tried different things, like clubQueryField(UserID) and clubQueryField.resolve, but with no luck
          UserID.Clubs = clubQueryField
          resolve([response]);
        });
      });
    }
  }
};

EDIT 3: UserType definition.

const UserType = new GraphQLObjectType({
  name: 'User',
  fields: () => ({
    UserID: {
      type: GraphQLID
    },
    Clubs: {
      type: new GraphQLList(ClubType)
    }
  })
});

GraphQL has a lazy loading feature that takes care of other fields in the query. If user writes the following query:

query{
   users{
    id
   }
}

it gets the user ids and it does not looking for other fields obviously. It definitely depends on your resolver though. If you write the resolver something like this: users { resolve: body => get_user_id} , it gets the user ids from the database. Hope this helps!

GraphQL APIs are organized in terms of types and fields, I recommend creating separate queries for User types and Club types, if someone is querying only userIds they will use the user query.

query for user:

query {
  users {
   id
  }
}

query for club:

query {
  club {
   clubID
   clubName
   userId
  }
}

if someone is trying to querying users/club you can add the club type to the User type like this:

query {
  users {
   id
   club {
    clubID
    clubName
   }
  }
}

in your user type there will be a field called club which is going to be type club and in the resolver it will call the club query with obj.userId as a parameter, the beauty of GraphQL is that you let the client decide what fields to fetch.

you can see an example of nested query here

EDIT: Then in your case you can modify your userType to include clubs where the user belongs to, you don't need that condition in your clubQueryField the condition will be on the query the client is making, so let say your user type is this:

UserType:

export default new GraphQLObjectType({
  name: 'UserType',
  fields: {
    userId: {
      description: 'user id',
      type: GraphQLString
    },
    email: {
      description: 'user email',
      type: GraphQLString
    },
    clubs: {
      description: 'User clubs',
      type: new GraphQLList(ClubType),
      resolve: (obj, args, _) => {
        return getUserClubs(obj.userId);
      }
    },
  }
});

then if your client needs only the user it will request something like this:

  query {
    User {
     userId
     email
     }
  }

and if the client needs user and clubs it will request something like this:

query {
    User {
     userId
     email
     clubs {
        field1
        field2
       }
     }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM