Skip to content

nuuday/gqlappsync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GqlAppSync

Description

GqlAppSync is a code-generating tool built on top of gqlgen, where the server and resolvers have been removed. It was created to add strongly-typed models for AWS AppSync.

Quick start

  1. Get the latest version of GqlAppSync go get github.com/nuuday/gqlappsync

  2. Define a schema.graphql file. E.g.:

type Book {
  title: String!
  author: Author!
}
type Query {
  books: [Book!]!
}

type Author {
  name: String!
}

Note: Doesn't currently support underscore in type names

  1. Define a gqlgen.yml file. E.g.:
# gqlgen.yml
# Where are all the schema file located?
schema:
  - ./schema.graphql

# Where should any generated models go?
model:
  filename: ./generated/models.gen.go
  package: generated

# This section declares type mapping between the GraphQL and go type systems
#
# The first line in each type will be used as defaults for resolver arguments and
# modelgen, the others will be allowed when binding to fields. Configure them to
# your liking
models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int64
      - github.com/99designs/gqlgen/graphql.Int32
  Int:
    model:
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int64
      - github.com/99designs/gqlgen/graphql.Int32
  AWSDateTime:
    model:
      - github.com/99designs/gqlgen/graphql.Time
  1. Generate models go run github.com/nuuday/gqlappsync

    The --config 'path' flag can be added to specify the path to the gqlgen.yml-filename

  2. Import and use the models in the lambdas

package main

import (
  "context"
  "todo/generated" // reference to the generated models
  "github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context) ([]generated.Book, error) {
  books := []generated.Book{
    {
      Title: "Clean Code",
      Author: &generated.Author{
        Name: "Robert Cecil Martin",
      },
    },
    {
      Title: "The Pragmatic Programmer",
      Author: &generated.Author{
        Name: "Andy Hunt and Dave Thomas",
      },
    },
  }
  return books, nil
}

func main() {
  lambda.Start(handler)
}

Working with interfaces and unions in AppSync and Go

Appsync can't differentiate between interface implementations or unions unless the __typename field is provided with the name of the type. Therefore all graphql types that implement an interface or are part of a union will have a Typename field generated with a json:"__typename"-tag. Currently, Go doesn't support custom default values, so the Typename field has to be assigned through the SetTypenameRecursively(x)method.

package main

import (
  "context"
  "todo/generated" // reference to the generated models
  "github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context) ([]generated.Book, error) {
  books := []generated.Book{ // Book is an interface
    generated.TextBook{// Textbook is an implementation of the interface
      Title: "Clean Code",
      Author: &generated.Author{
        Name: "Robert Cecil Martin",
      },
      SupplementaryMaterial: []generated.MediaItem{
        generated.AudioClip{
          Duration: 120,
        }
      },
    }
  }
  return generated.SetTypenameRecursively(books), nil // This is required for Appsync to know which type is being returned.
}

func main() {
  lambda.Start(handler)
}

Tip: Middleware

If the handler returns an interface that is implemented by a number of types that each would require invoking the SetTypenameRecursively(x)method, you could instead move the invocation to a lambda middleware.

func handler(ctx context.Context) (generated.Book, error) {
  if foo {
    return generated.Textbook{...}, nil
  }
  return generated.CookingBook{...}, nil
}
type handlerFunc func(context.Context) (generated.Book, error)

func SetTypename(f handlerFunc) handlerFunc {
  return func(ctx context.Context) (generated.Book, error) {
    response, err := f(ctx)
    response = generated.SetTypenameRecursively(response) // The invocation
    return response, err
  }
}

func main() {
  lambda.Start(SetTypename(handler))
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages