{ Josh Rendek }

<3 Go & Kubernetes

Here’s a sample application to show how to stitch together Buffalo, gqlgen and graphql subscriptions. Github Repo

I’ll go over the important parts here. After generating your buffalo application you’ll need a graphql schema file and a gqlgen config file:

1# schema.graphql
2type Example {
3	message: String
4}
5
6
7type Subscription {
8    exampleAdded: Example!
9}

and your config file:

 1# gqlgen.yml
 2struct_tag: json
 3schema:
 4- schema.graphql
 5exec:
 6  filename: exampleql/exec.go
 7  package: exampleql
 8model:
 9  filename: exampleql/models.go
10  package: exampleql
11resolver:
12  filename: exampleql/resolver.go
13  type: Resolver

Next lets generate our graphql files:

1go run github.com/99designs/gqlgen --verbose

Now we can open up our resolver.go file and add a New method to make creating the handler easier:

1func New() Config {
2	return Config{
3		Resolvers: &Resolver{},
4	}
5}

Let’s also add our resolver implementation:

 1func (r *subscriptionResolver) ExampleAdded(ctx context.Context) (<-chan *Example, error) {
 2	msgs := make(chan *Example, 1)
 3
 4	go func() {
 5		for {
 6			msgs <- &Example{Message: randString(50)}
 7			time.Sleep(1 * time.Second)
 8		}
 9	}()
10	return msgs, nil
11}
12
13var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
14
15func randString(n int) *string {
16	b := make([]rune, n)
17	for i := range b {
18		b[i] = letterRunes[rand.Intn(len(letterRunes))]
19	}
20	s := string(b)
21	return &s
22}

Inside your app.go file you’ll need to add a few handlers and wrap them in buffalo’s handler as well:

 1
 2c := cors.New(cors.Options{
 3	AllowedOrigins:   []string{"http://localhost:3000"},
 4	AllowCredentials: true,
 5})
 6
 7srv := handler.New(exampleql.NewExecutableSchema(exampleql.New()))
 8srv.AddTransport(transport.POST{})
 9srv.AddTransport(transport.Websocket{
10	KeepAlivePingInterval: 10 * time.Second,
11	Upgrader: websocket.Upgrader{
12		CheckOrigin: func(r *http.Request) bool {
13			return true
14		},
15	},
16})
17
18app.ANY("/query", buffalo.WrapHandler(c.Handler(srv)))
19
20app.GET("/play", buffalo.WrapHandler(playground.Handler("Example", "/query")))

Now if you head over to the playground and run this query:

1subscription {
2  exampleAdded {
3    message
4  }
5}

You should see something like this scrolling by:

  • This is not production ready code
  • If you were doing something with multiple load balanced nodes you should be using something like Redis or NATs pubsub to handle messaging
  • This isn’t cleaning up channels or doing anything that you should be doing for live code
comments powered by Disqus