A simple library to extract requested fields from a GraphQL request. Supports fragments, aliases and all GraphQL features.
import (
fields "github.com/gbaptista/requested-fields"
)
Examples of how to use with graphql-go and chi:
Create the query tree and pass it through context:
query := `{ user { name } }`
ctx := context.WithValue(request.Context(),
fields.ContextKey, fields.BuildTree(query))
Include a Field
field in all resolvers:
type Query struct {
Field fields.Field `graphql:"query"`
}
type UserResolver struct {
Field fields.Field `graphql:"user"`
}
Always set parent resolver on all resolvers. To access the fields use the fields.RequestedFor
function:
func (queryResolver *Query) User(ctx context.Context) *UserResolver {
userResolver := &UserResolver{}
userResolver.Field.SetParent(queryResolver)
log.Println(fmt.Sprintf(
"Query.User Fields: %v", fields.RequestedFor(ctx, userResolver)))
return userResolver
}
func (userResolver *UserResolver) Address(ctx context.Context) *AddressResolver {
addressResolver := &AddressResolver{}
addressResolver.Field.SetParent(userResolver)
log.Println(fmt.Sprintf(
"User.Address Fields: %v", fields.RequestedFor(ctx, addressResolver)))
return addressResolver
}
fields.RequestedForAt(ctx, queryResolver, "user.address")
fields.RequestedForAt(ctx, userResolver, "address")
fields.RequestedForAt(ctx, userResolver, "address.country")
For resources with different names:
type Article {
title: String
author: User
}
Use the SetCustomName
function:
func (articleResolver *ArticleResolver) Author(ctx context.Context) *UserResolver {
authorResolver := &UserResolver{}
authorResolver.Field.SetCustomName("author")
authorResolver.Field.SetParent(articleResolver)
return authorResolver
}
For a complete use example go to gbaptista/requested-fields-demo.
When aliases for the same resource are used at the same level:
{
user(id: 3) {
id
name
birthday
}
custom_user: user(id: 4) {
id
name
age
}
}
The requested fields will be the fields of all equal resources at the same level:
[]string{"id", "name", "birthday", "age"}
An alternative to this behavior is to use the BuildTreeUsingAliases
function:
{
user(id: 3) {
id
custom_name: name
birthday
}
custom_user: user(id: 4) {
id
name
age
}
}
The requested fields will be:
map[string][]string{
"": []string{"user", "custom_user"},
"user": []string{"id", "custom_name", "birthday"},
"custom_user": []string{"id", "name", "age"}}