Magnus
Magnus

Reputation: 7801

How do GraphQL arguments tie into fields?

I have read both the main "Learn" guide on graphql.com and the howtographql.com tutorial.

I am still struggling with a few concepts, one of them is relating to Arguments.

Basically, I do not understand how GraphQL knows what field of an Object type, a passed argument in a Query type belongs to.

Example:

type Person {
  id: ID!
  name: String!
  age: Int
  country: String!
}

type Query PersonsByAge {
  person(selectedCountry: String!): [Person]
}

query PersonsByAge {
  person(selectedCountry: 'Sweden')
}

Questions

  1. How exactly does GraphQL know that the selectedCountry argument should filter on the country field?
  2. Are there multiple instances of the Person Object type, like in normal OOP, strong textand these can be returned in a List as done above?
  3. I am not entirely confident my syntax / code above is correct, are there any obvious mistakes?

I feel like I am missing something really basic here, I just found that the guides lacked depth and structure.

Thank you.


EDIT:

Fixed parenthesis typo, pointed out in Daniel's answer. Did not fix other syntax issues, to keep the answer matching the question.

Upvotes: 0

Views: 5198

Answers (1)

Daniel Rearden
Daniel Rearden

Reputation: 84657

  1. Adding an argument or arguments for a particular field does not impact the value the field resolves to in itself. In GraphQL.js, every field has an associated resolve function (or "resolver"). It's up to the server to implement that function. The function receives four parameters, including the value of the parent field, the arguments for the field being resolved and the execution context. The resolver can use all or none of these parameters to determine the value that should be resolved for a field.

  2. Yes, GraphQL includes a special collection type called List that "declares the type of each item in the List". These can be input or output types or scalars. In GraphQL.js, a List is effectively just an array. It's important to note that if a field's type is a List, it's resolver must return an array, and, likewise, if a field's type is an output type, the resolver cannot return an array. GraphQL will not coerce a List into a non-List value and vice-versa.

  3. There's a couple of things wrong with your syntax. Your query has an extra parenthesis and no subselection for the person field (i.e. you don't specify the fields you want returned for that field, which is required since the type for the field is an output type, not a scalar). Additionally, in your schema definition, you've got an extraneous PersonsByAge label on your Query type which is invalid syntax and not really necessary.

Here's your example, reworked with correct syntax and a resolver to demonstrate the earlier point. This examples assumes you create your schema using graphql-tools.

const people = [
  { id: 1, name: 'Oscar', country: 'Sweden' },
  { id: 2, name: 'Sal', country: 'Italy' }
]
const typeDefs = `
  type Person {
    id: ID!
    name: String!
    country: String!
  }
  type Query {
    person(id: ID!): Person
    people(selectedCountry: String!): [Person]
  }
`
const resolvers = {
  Query: {
    person: (root, args, context) => {
      // this returns a single object
      return people.find(person => person.id === args.id)
    },
    people: (root, args, context) => {
      // this returns an array
      return people.filter(person => person.country === args.selectedCountry)
    },
  },
}

You may then query your schema client-side like this:

query SomeQueryName {
  people(selectedCountry: "Sweden") {
    id
    name
  }
}

I highly recommend checking out Apollo Launchpad, which will allow you to create a schema and query it on the fly so you can freely experiment with the syntax and learn by doing.

Upvotes: 4

Related Questions