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()
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.
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.
GraphQL works by sending operations to an endpoint. There are three types of operations: queries, mutations, and subscriptions.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With