Skip to content

GraphQL with Golang

February 24, 2023 | 01:00 AM

GraphQL is a popular query language and runtime for APIs developed by Facebook in 2012. It provides a more efficient, powerful, and flexible approach to building APIs compared to traditional REST APIs. GraphQL has gained a lot of traction in recent years due to its benefits such as reduced network overhead, client-driven data fetching, and the ability to specify precisely what data is required.

In this blog post, we will explore how to implement GraphQL with Golang, a popular programming language known for its concurrency features and performance.

What is GraphQL?

GraphQL is a query language that allows clients to request the exact data they need from a server. Unlike REST APIs, which often return too much or too little data, GraphQL allows clients to specify precisely what data they want and in what format. This makes it easier for clients to consume APIs and reduces the amount of data that needs to be transferred over the network.

GraphQL consists of three main components:

  1. Schema: A schema defines the types of data that can be queried and the operations that can be performed.
  2. Queries: Queries are requests made by clients to fetch data from the server. Queries specify the fields and data types that the client wants to retrieve.
  3. Mutations: Mutations are requests made by clients to modify data on the server. Mutations specify the fields and data types that the client wants to update.

Implementing GraphQL with Golang

Now that we have a basic understanding of GraphQL, let’s dive into how to implement it with Golang.

Step 1: Install the necessary packages

To implement GraphQL with Golang, we need to install the following packages:

You can install these packages using the following command:

go get github.com/graphql-go/graphql github.com/graphql-go/handler

Step 2: Define the GraphQL schema

The first step in implementing GraphQL with Golang is to define the schema. The schema defines the types of data that can be queried and the operations that can be performed.

Here is an example schema that defines a “user” type with two fields, “id” and “name”:

var userType = graphql.NewObject(graphql.ObjectConfig{
    Name: "User",
    Fields: graphql.Fields{
        "id": &graphql.Field{
            Type: graphql.Int,
        },
        "name": &graphql.Field{
            Type: graphql.String,
        },
    },
})

var schema, _ = graphql.NewSchema(graphql.SchemaConfig{
    Query: graphql.NewObject(graphql.ObjectConfig{
        Name: "Query",
        Fields: graphql.Fields{
            "user": &graphql.Field{
                Type: userType,
                Args: graphql.FieldConfigArgument{
                    "id": &graphql.ArgumentConfig{
                        Type: graphql.Int,
                    },
                },
                Resolve: func(params graphql.ResolveParams) (interface{}, error) {
                    id, ok := params.Args["id"].(int)
                    if ok {
                        // TODO: Fetch user from database
                    }
                    return nil, nil
                },
            },
        },
    }),
})

Step 3: Define the resolver

A resolver is a function that resolves a value for a type or field in a schema. In this step, you’ll define how to fetch data for each field in your schema.

func userResolver(params graphql.ResolveParams) (interface{}, error) {
    // Simulated data source
    users := []map[string]interface{}{
        {"id": 1, "name": "Alice"},
        {"id": 2, "name": "Bob"},
    }

    // Extract the id argument
    idQuery, isOK := params.Args["id"].(int)
    if isOK {
        for _, user := range users {
            if user["id"] == idQuery {
                return user, nil
            }
        }
    }
    return nil, nil
}

// Update the 'user' field definition in the schema
var schema, _ = graphql.NewSchema(graphql.SchemaConfig{
    Query: graphql.NewObject(graphql.ObjectConfig{
        Name: "Query",
        Fields: graphql.Fields{
            "user": &graphql.Field{
                Type: userType,
                Args: graphql.FieldConfigArgument{
                    "id": &graphql.ArgumentConfig{
                        Type: graphql.Int,
                    },
                },
                Resolve: userResolver,
            },
        },
    }),
})

Step 4: Handle the request

Finally, set up an HTTP server to handle requests to your GraphQL API.

import (
    "net/http"
    "github.com/graphql-go/handler"
)

func main() {
    // Create a GraphQL HTTP handler with our schema
    h := handler.New(&handler.Config{
        Schema: &schema,
        Pretty: true,
    })

    // Serve the GraphQL endpoint
    http.Handle("/graphql", h)
    println("GraphQL server is running on port 8080")
    http.ListenAndServe(":8080", nil)
}

This code will serve your GraphQL API at http://localhost:8080/graphql

Testing Your GraphQL API

To test your GraphQL API, you can use a tool like Postman or a GraphQL client like GraphiQL. Send a query to your server and see it in action. For example, a query to fetch user with id 1:

{
    user(id: 1) {
        id
        name
    }
}

Conclusion

By following these four steps - installing necessary packages, defining the GraphQL schema, creating resolvers, and setting up the server - you’ve now built a basic yet functional GraphQL API in Go. This combination leverages the strengths of GraphQL’s efficient data querying capabilities and Go’s performance and scalability. As you advance, consider integrating a database, adding authentication, and handling more complex queries to fully harness the power of GraphQL and Go.