Use Arguments in a GraphQL Query

Share this video with your friends

Send Tweet

In GraphQL, every field and nested object is able to take in arguments of varying types in order to do common operations like fetching an object by it's ID, filtering, sorting, and more. In this video, we'll update a field to take in an id argument and then learn how to use that argument in our resolve method to fetch a video by its id.

David Poindexter
David Poindexter
~ 8 years ago

Ran into a confusing error: getVideoById is not a function

Author was using es6 exports in getting-started/sr/data/index.js

If you run into this, just use normal node exports:

module.exports = {
    getVideoById: getVideoById
};
Josh Black
Josh Black(instructor)
~ 8 years ago

Hi there David! Wanted to say sorry for the confusion.

The syntax used for getVideoById doesn't actually leverage ES2015/ES6 Named Exports, it actually is using a default Node.js feature, similar to module.exports which you mentioned above. Since we are assigning the value of getVideoById explicitly on exports, the way that we import it changes.

For example:

// a.js
const b = require('./b');

b.foo();

// OR
const { foo } = require('./b');

b.foo();
// b.js
exports.foo = function foo() {
  // ...
}

Hope that helps!

Austin Witherow
Austin Witherow
~ 8 years ago

Thanks for the awesome tutorial :) Super useful that it was the one released today, as I am having to dive into some graphql stuff at work!

I am getting an error in graphiql, when I type in...

{
  video(id: "a") {
    title
  }
}

It says to me

{
  "errors": [
    {
      "message": "Unknown argument \"id\" on field \"video\" of type \"QueryType\".",
      "locations": [
        {
          "line": 2,
          "column": 8
        }
      ]
    }
  ]
}

My querytype looks correct from what I can see?

const queryType = new GraphQLObjectType({
  name: 'QueryType',
  description: 'the root query type',
  args: {
    id: {
      type: GraphQLID,
      description: 'id of the video'
    }
  },
  fields: {
    video: {
      type: videoType,
      resolve: (_, args) => getVideoById(args.id)
    }
  }
})

Any ideas?

Austin

Austin Witherow
Austin Witherow
~ 8 years ago

I figured it out. I accidentally put the args in under the GraphQLObjectType queryType instead of within the fields for video :)

Josh Black
Josh Black(instructor)
~ 8 years ago

Glad you figured it out! 😄 Sorry if there was any confusion!

~ 8 years ago

When using schema language, it seems that the args are the FIRST argument passed to my resolver. I noticed in the docs it says that the function signature for a resolver is usually (obj, args, context) => {...}

obj The previous object, which for a field on the root Query type is often not used.

Could you elaborate on this? It seems strange that the arguments passed to the resolver fn could be different.

Josh Black
Josh Black(instructor)
~ 8 years ago

Hi there! First off, wanted to say thanks for watching.

It seems strange that the arguments passed to the resolver fn could be different.

That's a great point, and I think the reason for that only comes from when you have a field that needs to be fetched/computed outside of the initial resolve function.

Say we have the following schema:

type User {
  name: String
  friends: [User]
}

type Query {
  user(id: ID!): User
}

Our resolve function for the user field will probably look like:

resolve: (rootObject, args, context) => {
  /**
   * Some promise-returning function that returns a user-object,
   * for example: { id: 'abcd', name: 'Josh Black', friends: [1, 2, 3] }
   * where `friends` is an array of ids
   */
  return userLoader.load(args.id);
}

This resolve function will satisfy the name part of the User type, however it's not sure how to handle the friends bit. We can try and pre-load the friends in this initial call, and that will definitely work out, or we can delegate to the friends field on the User type to figure out how to resolve that for us.

In the latter case, we'll need access to object in order to get the list of friend ids. A resolve function for that might look like:

resolve: (user) => {
  return userLoader.loadMany(user.friends);
}

So since we have access to the current object, we can take fields off of that object in order to fully resolve the field.

Hope that helps! Feel free to ask more questions if that example didn't cover exactly what you were looking for.

Sameh
Sameh
~ 7 years ago

instead of

[video] = vidoes.filter...

its a better idea to use

const video = videos.find...
Leonel Galán
Leonel Galán
~ 4 years ago

Clever use of array destructuring: instead of video = videos.filter(...)[0] => [video] = videos.filter(...). I've seen many destructuring assignments, but first time I see this.

@Sameh, It's not necessarily better. But yeah, your alternative should works just the same.