GraphQL in Go: golang graphql tutorial, examples, and HTTP server

Graphql golang tutorial and golang graphql example with github.com/graphql-go/graphql: schema, resolvers, graphql.Do, context, HTTP handler and Playground, go graphql patterns, graphql golang vs REST, and graphql mongodb golang notes with Mongo driver and resolvers.

Published

Updated

Read time 5 min read

Reviewed byDeepak Prasad

GraphQL in Go: golang graphql tutorial, examples, and HTTP server

This page is a graphql golang tutorial in the narrow sense: it shows golang graphql and go graphql examples using graphql-go/graphql, which builds schemas in Go and executes operations with graphql.Do. If you searched graphql golang example, golang graphql example, or graphql golang tutorial, you will get a minimal schema, a resolver that reads context, and an HTTP server with Playground. Searches for graphql mongodb golang or golang graphql mongodb are covered in a short dedicated subsection—GraphQL stays agnostic to storage, and MongoDB lives behind your resolvers.

Tested with Go 1.24 on Linux.


GraphQL and Go at a glance

GraphQL is a query language and runtime: the client sends a document describing the shape of data it wants, and the server walks a typed graph you define. graphql go stacks usually pair a schema library (here graphql-go) with net/http or a router. graphql go differs from typical REST in that one POST handler can serve many “logical endpoints” encoded as queries.


Golang graphql example: define a schema and run graphql.Do

Install the library in your module:

bash
go get github.com/graphql-go/graphql@latest

The program below defines a single hello field on the root query type and prints the JSON-like result of graphql.Do.

go
package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/graphql-go/graphql"
)

func main() {
	fields := graphql.Fields{
		"hello": &graphql.Field{
			Type: graphql.String,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return "Welcome to GoLinuxcloud!", nil
			},
		},
	}
	rootQuery := graphql.ObjectConfig{Name: "RootQuery", Fields: fields}
	schema, err := graphql.NewSchema(graphql.SchemaConfig{
		Query: graphql.NewObject(rootQuery),
	})
	if err != nil {
		log.Fatalf("schema: %v", err)
	}
	query := `{ hello }`
	r := graphql.Do(graphql.Params{Schema: schema, RequestString: query})
	if len(r.Errors) > 0 {
		log.Fatalf("errors: %+v", r.Errors)
	}
	out, _ := json.Marshal(r)
	fmt.Println(string(out))
}
Output

Running go run . prints one line of JSON containing data.hello with the welcome string.


Resolvers, arguments, and context

Resolvers receive graphql.ResolveParams: p.Args holds GraphQL arguments, and p.Context carries request-scoped values from the standard context package (auth, tracing, database handles).

go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"github.com/graphql-go/graphql"
)

func main() {
	schema, err := graphql.NewSchema(graphql.SchemaConfig{
		Query: graphql.NewObject(graphql.ObjectConfig{
			Name: "Query",
			Fields: graphql.Fields{
				"value": &graphql.Field{
					Type: graphql.String,
					Args: graphql.FieldConfigArgument{
						"key": &graphql.ArgumentConfig{Type: graphql.String},
					},
					Resolve: func(p graphql.ResolveParams) (interface{}, error) {
						return p.Context.Value(p.Args["key"]), nil
					},
				},
			},
		}),
	})
	if err != nil {
		log.Fatal(err)
	}
	query := `{ value(key:"User1") }`
	result := graphql.Do(graphql.Params{
		Schema:        schema,
		RequestString: query,
		Context:       context.WithValue(context.TODO(), "User1", "xyz"),
	})
	out, _ := json.Marshal(result)
	fmt.Println(string(out))
}
Output

Running it prints JSON where data.value is xyz, showing the key from the query mapped through p.Args into context.Value.


GraphQL HTTP server with Playground (graphql golang tutorial)

For browsers and API gateways you expose GraphQL over HTTP. The graphql-go/handler package wraps a graphql.Schema as an http.Handler and can enable GraphQL Playground for local experiments.

bash
go get github.com/graphql-go/handler@latest

The following self-contained server keeps sample students in a string constant (no data.json on disk). Save as main.go, run go run ., and open http://localhost:8080/graphql for Playground while it is running.

go
package main

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"

	"github.com/graphql-go/graphql"
	"github.com/graphql-go/handler"
)

const dataJSON = `[
  {"id":1,"name":"Dan","passed":true},
  {"id":2,"name":"Bob","passed":true}
]`

var students []*Student

type Student struct {
	ID     int    `json:"id"`
	Name   string `json:"name"`
	Passed bool   `json:"passed"`
}

func listStudents() ([]*Student, error) { return students, nil }

func getStudent(id int) (*Student, error) {
	for _, s := range students {
		if s.ID == id {
			return s, nil
		}
	}
	return nil, errors.New("student not found")
}

func main() {
	if err := json.Unmarshal([]byte(dataJSON), &students); err != nil {
		log.Fatal(err)
	}
	studentType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Student",
		Fields: graphql.Fields{
			"id": &graphql.Field{
				Type: graphql.Int,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					if s, ok := p.Source.(*Student); ok {
						return s.ID, nil
					}
					return nil, nil
				},
			},
			"name": &graphql.Field{
				Type: graphql.String,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					if s, ok := p.Source.(*Student); ok {
						return s.Name, nil
					}
					return nil, nil
				},
			},
			"passed": &graphql.Field{
				Type: graphql.Boolean,
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					if s, ok := p.Source.(*Student); ok {
						return s.Passed, nil
					}
					return nil, nil
				},
			},
		},
	})
	queryType := graphql.NewObject(graphql.ObjectConfig{
		Name: "Query",
		Fields: graphql.Fields{
			"students": &graphql.Field{
				Type: graphql.NewList(studentType),
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					return listStudents()
				},
			},
			"student": &graphql.Field{
				Type: studentType,
				Args: graphql.FieldConfigArgument{
					"id": &graphql.ArgumentConfig{Type: graphql.NewNonNull(graphql.Int)},
				},
				Resolve: func(p graphql.ResolveParams) (interface{}, error) {
					return getStudent(p.Args["id"].(int))
				},
			},
		},
	})
	schema, err := graphql.NewSchema(graphql.SchemaConfig{Query: queryType})
	if err != nil {
		log.Fatal(err)
	}
	h := handler.New(&handler.Config{
		Schema:     &schema,
		Pretty:     true,
		GraphiQL:   false,
		Playground: true,
	})
	http.Handle("/graphql", h)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Example query in Playground:

graphql
{
  students { id name passed }
}

Example query with an argument:

graphql
{
  student(id: 1) { name }
}

Turn off Playground and GraphiQL before exposing the handler on the public internet.

Graphql mongodb golang and golang graphql mongodb

GraphQL does not speak MongoDB directly: your resolvers are plain Go functions. A typical golang graphql mongodb layout is: connect with mongo.Connect in main, obtain a *mongo.Collection, then either close over that collection in resolver functions or store it in context.Context (for example with a private context key type) so each Resolve can run FindOne, InsertOne, or aggregation pipelines. That keeps protocol concerns in GraphQL and persistence in the driver. For CRUD basics without GraphQL, read Golang MongoDB first, then lift the same calls into resolvers.


gqlgen and other stacks

This graphql golang tutorial uses code-first schema construction. For SDL-first code generation and stricter typing, many teams choose gqlgen. Both are valid answers to graphql go depending on project size and whether you want .graphql files as the source of truth.


Summary

A practical graphql golang tutorial for small services starts with graphql.NewSchema, graphql.Do for scripts, and graphql-go/handler for HTTP. golang graphql example code boils down to types built with graphql.NewObject, field resolvers that return Go values, and optional arguments plus context for per-request data. graphql mongodb golang work is ordinary Mongo driver usage inside those resolvers, not a separate GraphQL feature. Compare approaches (graphql-go versus gqlgen), disable Playground in production, and keep learning HTTP details in the Go HTTP guide.


References


Frequently Asked Questions

1. What is the simplest golang graphql example?

Define fields with graphql.Field, build a graphql.Schema with graphql.NewSchema, then run graphql.Do with your query string; the result is JSON-compatible data plus errors.

2. How does this graphql golang tutorial relate to REST?

GraphQL exposes one HTTP endpoint where clients choose fields; you still use net/http, but the handler parses GraphQL bodies instead of mapping one path per resource.

3. How do I wire graphql mongodb golang or golang graphql mongodb?

Keep GraphQL types in the API layer: open a *mongo.Collection in main, pass it into resolvers (closure or context.Value), and run queries inside Resolve using the official Go driver—see the MongoDB guide linked in the body.

4. Should I use graphql-go or gqlgen for go graphql?

graphql-go/graphql is small and code-first; gqlgen generates Go from schema and scales better for large teams—pick based on whether you want hand-written schema in Go or SDL-first workflows.

5. Is GraphQL Playground safe in production?

No: disable Playground and GraphiQL on public servers; use them only on developer machines or protected environments.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …