Buffalo, gqlgen, and graphql subscriptions
Mar 21, 2020 - 2 minutesHere’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