Skip to content

Instantly share code, notes, and snippets.

@calam1
Last active April 11, 2021 20:40
Show Gist options
  • Save calam1/19cbd3ceef2d903f99a3c1696b94bdc1 to your computer and use it in GitHub Desktop.
Save calam1/19cbd3ceef2d903f99a3c1696b94bdc1 to your computer and use it in GitHub Desktop.
some code snippets for gqlgen dataloader
I learned a lot from watching this youtube video - https://www.youtube.com/watch?v=D3SrjuTaUQU
// Gin Route File
import (
...
"github.com/mycompany/menu/graph/dataloader/meal_tag"
)
func Routes(r *gin.Engine) {
...
mealTagDataloader := meal_tag.NewMealTagDataloader()
...
rg := r.Group("/mysite")
rg.Use(
...
meal_tag.MealTagLoaderMiddleware(productRepository),
...
{
rg.POST("query", serverutils.GraphqlHandler(productRepository, mealTagDataloader))
}
}
// graphql handler file
func GraphqlHandler(productRepo productRepo.ProductRepository, mealTagDataloader meal_tag.MealTagDataloader) gin.HandlerFunc {
h := handler.New(gqlGen.NewExecutableSchema(gqlGen.Config{
Resolvers: &resolvers.Resolver{
ProductRepository: productRepo,
...
MealTagDataloader: mealTagDataloader,
...
},
Complexity: gqlGen.ComplexityRoot{},
}))
h.AroundOperations(func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
rc.DisableIntrospection = cfg.GraphQLDisableIntrospection
return next(ctx)
})
h.Use(extension.FixedComplexityLimit(cfg.GraphQLComplexityCount))
return func(c *gin.Context) {
h.AddTransport(transport.GET{})
h.AddTransport(transport.POST{})
h.ServeHTTP(c.Writer, c.Request)
}
}
// Dataloader file
const mealTagsLoaderKey = "mealTagsLoader"
func MealTagLoaderMiddleware(productRepo productRepo.ProductRepository) gin.HandlerFunc {
return func(c *gin.Context) {
mealTagLoader := MealTagLoader{
maxBatch: 100,
wait: 5 * time.Millisecond,
fetch: func(ids []int) ([]*string, []error) {
mealTags, err := productRepo.MealTagAllergens(c, ids)
if err != nil {
log.Errorf("error in mealTagLoaderMiddleware retrieving mealTags %v", err)
return nil, []error{err}
}
return buildMealTagsAndSort(ids, mealTags)
},
}
ctx := context.WithValue(c.Request.Context(), mealTagsLoaderKey, &mealTagLoader)
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
func buildMealTagsAndSort(ids []int, mealTags []*model.MealTag) ([]*string, []error) {
... do some stuff
result := make([]*string, len(ids))
... do some more stuff
return result, nil
}
type MealTagDataloader interface {
GetMealTagLoader(ctx context.Context) *MealTagLoader
}
type MealTagDataloaderImpl struct{}
func NewMealTagDataloader() *MealTagDataloaderImpl {
return &MealTagDataloaderImpl{}
}
func (m *MealTagDataloaderImpl) GetMealTagLoader(ctx context.Context) *MealTagLoader {
return ctx.Value(mealTagsLoaderKey).(*MealTagLoader)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment