GraphQL Library Go (Golang) — A Powerful Tool for Creating APIs
GraphQL is a query language for APIs that allows clients to request only the data they actually need. In the Go (Golang) ecosystem, one of the most popular libraries for working with GraphQL is gqlgen (GraphQL Go Generate). This library allows you to create type-safe GraphQL servers with minimal boilerplate code. In this article, we will thoroughly cover gqlgen, its installation, configuration, and usage examples.
What is gqlgen?
gqlgen is a code generator for Go that automatically creates resolvers and types based on your GraphQL schema. Key advantages:
- Type safety — all types are checked at compile time
- Minimal boilerplate — the library generates most of the code for you
- Flexibility — support for subscriptions, mutations, and complex queries
- Performance — high speed characteristic of Go
Installing gqlgen
To get started, install the library and the command-line utility:
go get github.com/99designs/gqlgengo run github.com/99designs/gqlgen initThe init command will create a basic project structure with the files schema.graphqls, gqlgen.yml, and generated code.
Project Structure
After initialization, you will get the following structure:
my-graphql-app/├── gqlgen.yml # Generator configuration├── graph/│ ├── schema.graphqls # GraphQL schema│ ├── resolver.go # Resolvers (your code)│ └── models_gen.go # Generated models (do not edit)├── server.go # Entry point└── go.modWriting a GraphQL Schema
Example of a schema.graphqls file for a simple blog:
type Query { posts: [Post!]! post(id: ID!): Post}
type Mutation { createPost(input: PostInput!): Post! deletePost(id: ID!): Boolean!}
type Post { id: ID! title: String! content: String! author: String! createdAt: Time!}
input PostInput { title: String! content: String! author: String!}
scalar TimeCode Generation
After describing the schema, run:
go run github.com/99designs/gqlgen generateThis will create the models_gen.go and generated.go files with types and resolver interfaces.
Implementing Resolvers
Now you need to implement the logic in resolver.go:
package graph
import ( "context" "time")
// Data modeltype Post struct { ID string `json:"id"` Title string `json:"title"` Content string `json:"content"` Author string `json:"author"` CreatedAt time.Time `json:"createdAt"`}
// In-memory storagevar posts = []*Post{ { ID: "1", Title: "Introduction to GraphQL", Content: "GraphQL is a query language...", Author: "Ivan Petrov", CreatedAt: time.Now(), },}
// Resolver for Query.postsfunc (r *queryResolver) Posts(ctx context.Context) ([]*Post, error) { return posts, nil}
// Resolver for Query.postfunc (r *queryResolver) Post(ctx context.Context, id string) (*Post, error) { for _, post := range posts { if post.ID == id { return post, nil } } return nil, nil}
// Resolver for Mutation.createPostfunc (r *mutationResolver) CreatePost(ctx context.Context, input PostInput) (*Post, error) { newPost := &Post{ ID: fmt.Sprintf("%d", len(posts)+1), Title: input.Title, Content: input.Content, Author: input.Author, CreatedAt: time.Now(), } posts = append(posts, newPost)