Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are nested GraphQL queries with specific id values possible?

Tags:

graphql

I've successfully built a GraphQL API which allows nested queries. Using the generic examples of Countries & States, I can perform a query like this:

    query{
      country(id:"Q291bnRyeTo0Nw==") {
        states {
          edges {
            node {
              id,
              name,
              area,
              population
            }
          }
        }
       }
     }

What I've discovered I can't seem to do is this:

query{
      country(id:"Q291bnRyeTo0Nw==") {
        state(id:"U3RhdGU6MzM=") {
          edges {
            node {
              id,
              name,
              area,
              population
            }
          }
        }
      }
    }

Might there be a way with GraphQL to specify a specific parent and specific child in one query?

Robert

Update: For Daniel's benefit, here is my current GraphQL Query code:

from .models import Country as CountryModel
from .models import State as StateModel

class Query(graphene.AbstractType):

    country = graphene.Field(Country, id=graphene.String())
    countries = graphene.List(Country)

    state = graphene.Field(State, id=graphene.String())
    states = graphene.List(State)

    def resolve_country(self, args, context, info):
        id = args.get('id')

        if id is not None:
            return CountryModel.objects.get(id=Schema.decode(id))
    
        return None

    def resolve_countries(self, args, context, info):
        return CountryModel.objects.all()

    def resolve_state(self, args, context, info):
        id = args.get('id')

        if id is not None:
            return StateModel.objects.get(id=Schema.decode(id))
    
        return None

    def resolve_states(self, args, context, info):
        return StateModel.objects.all()
like image 678
Robert_LY Avatar asked Aug 09 '17 16:08

Robert_LY


People also ask

Can you nest queries in GraphQL?

GraphQL queries allow us to pass in arguments into query fields and nested query objects. You can pass arguments to every field and every nested object in your query to further deepen your request and make multiple fetches.

What is ID type in GraphQL?

ID : The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable.

What are the three types of operations in GraphQL?

GraphQL works by sending operations to an endpoint. There are three types of operations: queries, mutations, and subscriptions.


1 Answers

You'd need to define a resolver for both the country field on the Root Query and the state field on the Country type. Here's an example you can copy and paste into Launchpad and see it in action.

The set up for something like Graphene would be a little different, but the idea is the same: the object returned by your country query is made available to the resolver for every field under the state type. You use the id argument passed to the state field to filter the data on that object (in this example, the returned object has a states property) and return the appropriate state.

import { makeExecutableSchema } from 'graphql-tools';

const countries = [
  {
    id: 1,
    name: 'bar',
    states: [
      {
        name: 'foo',
        id: 20
      }
    ]
  },
  { id: 2 },
];

const typeDefs = `
  type Query {
    country(id: Int!): Country
  }
  type Country {
    id: Int
    state(id: Int!): State
  }
  type State {
   id: Int
   name: String
  }
`

const resolvers = {
  Query: {
    country: (obj, args, context) => {
      return countries.find(country => country.id === args.id)
    },
  },
  Country: {
    state: (obj, args, context) => {
      return obj.states.find(state => state.id === args.id)
    },
  }
}

export const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
})

Edit: Assuming the object returned by CountryModel.objects.get(id=Schema.decode(id)) includes a states attribute that is a list of states, you should be able to do something like:

class Country(graphene.ObjectType):
  state = graphene.Field(State,
                          id=graphene.String()
                          )
  # other fields
  def resolve_state(self, args, context, info):
    id = args.get('id')
    if id is not None:
        return list(filter(lambda x: x.id == id, self.states)
    return None
like image 102
Daniel Rearden Avatar answered Sep 29 '22 11:09

Daniel Rearden