简体   繁体   中英

GraphQL: Use input type and one of its fields in the same query

I'm wondering how to use both an input type and one of its fields as arguments in the same GraphQL query. I think there are a few valid solutions, but I'm wondering which (if any) are best practice.

Consider the following hypothetical query. We get players by location and status, and team members who are in the same location, but the member field only has a location argument:

input PlayerInput {
  location: String!
  status: Int!
}

query getPlayers($playerInput: PlayerInput) {
  players(playerInput: $playerInput) {
    name
    team {
      name
      members(location: ???) { // <-- How to access playerInput.location?
        name
      }
    }
  }
}

I can think of a few ways to solve this:

1. Change the query to take individual arguments

query getPlayers($location: String!, $status: Int!) {
  players(playerInput: { location: $location, status: $status }) {
    name
    team {
      name
      members(location: $location) {
        name
      }
    }
  }
}

2. Update the schema so members takes the right input type

query getPlayers($playerInput: PlayerInput) {
  players(playerInput: $playerInput) {
    name
    team {
      name
      members(playerInput: $playerInput) { // <-- Requires changing schema
        name
      }
    }
  }
}

This doesn't seem great for a few reasons, and would only work if you have the ability to update the schema.

3. Pass location in as a redundant individual argument

query getPlayers($playerInput: PlayerInput, $location: String!) {
  players(playerInput: $playerInput) {
    name
    team {
      name
      members(location: $location) {
        name
      }
    }
  }
}

This seems fine, just that there's some duplication when creating the query:

const location = 'US';
const status = 1;

fetch({
  query: getPlayersQuery,
  variables: {
    location,
    playerInput: {
      location,
      status,
    }
  }
})...

Are any of these the preferred way of doing something like this? Are there other ways I haven't considered?

Utilizing multiple arguments over a single argument that takes an input type (option #1) sometimes makes sense conceptually , but it lacks any other real merit and has the downside of making your variable definitions unnecessarily verbose. In my opinion, using input types typically enforces typings better as well. Changing your schema just to avoid duplication is not worth it.

Utilizing the same input object type on both fields (option #2) should only be done if both fields actually need all those input fields. Doing it just to avoid duplication is a bad idea -- it effectively introduces inputs that are unused, which is not a good experience for any other developer consuming the API.

Option #3 is fine. It also puts the ball in the front end dev's court -- if they wanted to avoid the duplication, they could also just as easily do this without you introducing additional arguments:

query getPlayers($status: Int!, $location: String!) {
  players(playerInput: { status: $status, location: $location }) {
    name
    team {
      name
      members(location: $location) {
        name
      }
    }
  }
}

However, the duplication is most likely actually a good thing. You don't encounter these scenarios too much in the wild because we're dealing with graphs of data. The players , team and members fields are all part of a hierarchy, where the parent field constrains the data returned by the child -- for example, members doesn't return all members, just members of that particular team. That means, in most cases if you constrain players to only include data from a particular location, you're also constraining the data returned by child fields like members . If you feel like members needs its own location argument, then that implies that the two location inputs could be different . If they could be different, they should be represented as two separate variables to maximize flexibility and query reuse.

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