Golang GraphQL API Development with Gqlgen

Author

Reads 1.3K

From above crop faceless male developer in black hoodie writing software code on netbook while working in light studio
Credit: pexels.com, From above crop faceless male developer in black hoodie writing software code on netbook while working in light studio

Golang GraphQL API Development with Gqlgen is a powerful combination that can help you build scalable and efficient APIs. Gqlgen is a popular Go library for generating GraphQL APIs.

With Gqlgen, you can define your GraphQL schema using Go types and then generate the necessary code for your API. This approach makes it easy to evolve your schema over time.

Gqlgen also integrates well with other popular Go frameworks, making it a great choice for building production-ready APIs.

In this section, we'll explore how to use Gqlgen to build a GraphQL API in Go.

Getting Started

To get started with Golang GraphQL, you'll need to install gqlgen and initialize your project. Fetch the library using the command `go get github.com/99designs/gqlgen` and add gqlgen to your project's tools.go file.

You'll then need to initialize the gqlgen config and generate the models. This will create a directory called `graphql` with various files and folders, including `model/model_gen.go` and `generated/generated.go`. These files should not be modified manually, as they will be updated by gqlgen as you modify your schema.

To define your schema from scratch, delete everything in the `schema.graphqls` file and start fresh. This file uses the schema-definition-language (SDL) to describe data types and operations in a human-readable way.

For more insights, see: Golang Go

Getting Started with gqlgen

Credit: youtube.com, Part 1 - Setup of GQLGen

To get started with gqlgen, you'll need to install it and initialize your project. You can fetch the library using the command `go get github.com/99designs/gqlgen`, then add it to your project's tools.go file. This will set up the necessary configurations for your gqlgen workspace.

Create a directory for your project and initialize it as a Go Module using `go mod init`. Next, create a tools.go file and add gqlgen as a tool dependency for your module. To automatically add the dependency to your go.mod file, run `go get -u github.com/99designs/gqlgen`.

You'll then need to initialize your gqlgen config and generate models. This will create your suggested package layout, which you can modify if needed. The generated files will include a gqlgen.yml config file, a graph directory with generated code, and a schema.graphqls file where you'll define your GraphQL schema.

Here are the key files to pay attention to:

  • schema.graphqls: This is where you'll define your GraphQL schema using schema-definition-language (SDL).
  • schema.resolvers.go: This file contains wrapper code for queries and mutations defined in schema.graphqls.
  • model/model_gen.go: This file contains structs generated by gqlgen, defined by the schema file schema.graphqls.
  • generated/generated.go: This file contains generated code that injects context and middleware for each query and mutation.

Remember, you should not modify the model/model_gen.go and generated/generated.go files, as they will be modified by gqlgen as you update your schema.

Introduction: Why GraphQL?

Credit: youtube.com, GraphQL Explained in 100 Seconds

GraphQL has emerged as a promising alternative to traditional REST APIs. It offers a query language similar to SQL, allowing you to retrieve specific data through a single query.

One of the main advantages of GraphQL is that it improves efficiency and reduces network traffic. This is because you can retrieve specific data through a single query, rather than relying on multiple requests to various endpoints.

Complex use cases and deeply nested data are becoming more common, and GraphQL provides more flexibility for other developers to consume your API. This flexibility is especially useful for applications that require sophisticated data relationships.

By using GraphQL, you can avoid issues with documentation and over/under-fetching of data that are common with REST APIs.

Additional reading: Golang Rest Api

GQLGen Overview

gqlgen is a Go library for building GraphQL servers without any fuss. It's based on a Schema first approach, which means you get to define your API using the GraphQL Schema Definition Language.

Credit: youtube.com, GraphQL in Go - GQLGen Tutorial

gqlgen prioritizes Type safety, ensuring you never see map[string]interface{} here. This is a big deal, as it helps prevent errors and makes your code more maintainable.

To get started with gqlgen, you'll need to initialise its config and generate models. This is a straightforward process that sets the stage for building your GraphQL API.

Here are the key benefits of using gqlgen:

  • Based on a Schema first approach
  • Prioritizes Type safety
  • Enables Codegen

gqlgen enables codegen, which means it generates the boring bits, so you can focus on building your app quickly. This is a huge time-saver, especially for complex GraphQL APIs.

Once you've set up your gqlgen workspace, you can start modifying your resolver.go file to add dependencies. This is where you can inject dependencies like DB Clients into your resolvers.

GraphQL Schema

To build a GraphQL schema, we'll start with the basics. We'll define a simple type for our To-Do application. The type will have just three fields: id, text, and done.

For your interest: Golang Types

Credit: youtube.com, What is a GraphQL Schema?

For our To-Do application, we need GraphQL mutations to create, mark as done, and remove tasks. This will help generate the necessary code for our queries and mutations.

To keep things simple, we'll narrow the fields to just id, text, and done. This is a good starting point for building our GraphQL schema.

We can customize the degree of concurrency for our field resolvers by adjusting the worker_limit configuration attribute. This allows us to control how many goroutines are used to execute the resolvers concurrently.

Generating and Running Code

You'll need to generate code to update the files schema.resolvers.go, model/models_gen.go, and generated/generated.go. To do this, delete the example code in schema.resolvers.go and run the command to update these files.

After running the command, you can see that the files have been updated by running git diff. This will show you the changes made to the files.

You can confirm that the API can still run by running a simple query. However, you'll encounter an error because you haven't defined the resolver code yet. Let's do that next by modifying the schema in schema.graphqls.

Credit: youtube.com, JWT Authorization in GRAPHQL API using Golang | GRAPHQL Golang

Here's a list of files that will be updated:

  • schema.resolvers.go
  • model/models_gen.go
  • generated/generated.go

Note that the code generator will move previously defined methods, so you may see some code that looks like this:

```go

func (r *Resolver) Characters(ctx context.Context, obj *model.Character) ([]*model.Character, error) {

// old code here

}

```

You can remove this code since it's not doing anything.

Building the Server

The gqlgen generate command compares the schema file (graph/schema.graphqls) with the models graph/model/*.

This comparison is done to bind directly to the model wherever possible, which was already done when the init command was run.

If you encounter the error "no Go files" while executing the generate command, follow the instructions in the comment for a possible solution.

gqlgen generates code that updates several files, including schema.resolvers.go, model/models_gen.go, and generated/generated.go.

Best Practices

When writing a Go GraphQL schema, it's essential to keep it organized and maintainable. This can be achieved by using a consistent naming convention, such as using camelCase for field names.

Credit: youtube.com, Dynamic GraphQL with Go - Kenneth Shaw

Use enums to define a fixed set of values, like in the example where we defined a color enum with red, blue, and green values. This helps prevent typos and makes the code more readable.

To avoid unnecessary complexity, break down large types into smaller ones. For instance, instead of having a single type for a user, we can have separate types for user details, address, and contact information.

Avoid rushing user fetches

Avoid rushing user fetches. Fetching most objects is expensive, so it's best to load the User on the todo only when the user actually asked for it.

In a real-world scenario, loading the User object can be costly, so it's essential to optimize this process. To achieve this, we can enable autobind in gqlgen, allowing it to use our custom models instead of generating them.

Autobind can be enabled by uncommenting the autobind config line in gqlgen.yml. This allows gqlgen to use our custom models if it can find them, reducing unnecessary loads.

By implementing autobind, we can improve the efficiency of our application, making it more scalable and user-friendly.

Suggestion: S Golang

Prevent Fetching Unused Child Objects

From above crop anonymous male programmer in black hoodie working on software code on contemporary netbook and typing on keyboard in workspace
Credit: pexels.com, From above crop anonymous male programmer in black hoodie working on software code on contemporary netbook and typing on keyboard in workspace

You can prevent fetching child objects that might not be used by telling gqlgen to only fetch them when requested. This is especially useful when dealing with nested or recursive schema.

To do this, you can enable autobind in gqlgen.yml, allowing gqlgen to use your custom models if it can find them rather than generating them. This is done by uncommenting the autobind config line.

In the case of a schema like this, you need to tell gqlgen to only fetch friends if the user requested it. There are two ways to do this.

One way is to add Todo fields resolver config in gqlgen.yml to generate resolver for user field. This will allow gqlgen to use your custom model and only fetch the user field when requested.

The other way to prevent fetching child objects is to use a custom resolver that checks if the user requested the child object before fetching it.

Expand your knowledge: Golang Use Cases

Customizing GQLGen

Credit: youtube.com, Learn Go by building small projects - P02EP02 Using GQLGen for the GraphQL Layer

Customizing GQLGen can be a powerful way to tailor your GraphQL schema to your specific needs. You can write a custom model that omits certain fields, like the friends field, and reference it in your gqlgen.yml file.

To enable autobind, you can uncomment the autobind config line in gqlgen.yml, which allows gqlgen to use your custom models instead of generating them. You can also add Todo fields resolver config in gqlgen.yml to generate a resolver for the user field.

If you'd prefer not to have getters generated in your interfaces, you can add a specific configuration to your gqlgen.yml file. This can be useful if you're working with Relay-style Connections, which can't be implemented with simple getters.

Gqlgen Configuration

Gqlgen Configuration is a crucial aspect of customizing GQLGen. You can configure nearly everything from file directories for generated files to complex tasks like linking GraphQL schema types to existing Go structures.

Gqlgen allows you to configure file directories for generated files, which can help you manage your project's structure more efficiently.

Credit: youtube.com, Field-Level Caching for Go GqlGen!

You can also configure other items such as turning on gqlgen tags, disabling and enabling slice pointers, and automatically binding existing Go structures within a package to corresponding GraphQL types. This can provide greater versatility in the development process.

Here are some specific configuration options you can use:

  • gqlgen tags: Instead of using JSON tags in Go structs, you can use the gqlgen:fieldName tag
  • Disable and enable slice pointers
  • Automatically bind existing Go structures within a package to corresponding GraphQL types
  • And so much more (see here for more information)

You can break up your schemas into multiple files with gqlgen to manage your resolvers easier. This can help you keep your code organized and maintainable.

To configure Gqlgen, you'll need to modify your gqlgen.yml file. One of the configuration options you can use is to disable getters in interfaces. This can be done by adding the following line to your gqlgen.yml file:

However, certain fields, like Relay-style Connections, cannot be implemented with simple getters. If you'd prefer to not have getters generated in your interfaces, you can add the following configuration option.

Using Custom Models

Using custom models is a great way to fine-tune your GQLGen setup. You can write a custom model that omits the friends field.

Credit: youtube.com, Dynamically Generate GraphQL Schemas for Customizable Tables

To do this, you'll need to reference the model in your gqlgen.yml file. This is a crucial step in using custom models.

By referencing the custom model, you're telling GQLGen to use your custom code instead of generating it from the schema. This can be especially helpful when you have existing Go structures that you want to link to your GraphQL types.

You can also configure GQLGen to autobind your custom models. This means that if a struct within a "models" directory shares the same name as a GraphQL type, GQLGen will prioritize the existing struct rather than create a new one.

Here's a list of some other things you can configure in gqlgen.yml:

  • Turning on gqlgen tags
  • Disabling and enabling slice pointers
  • Automatically binding existing Go structures within a package to corresponding GraphQL types

By taking advantage of these features, you can make your GQLGen setup more flexible and efficient.

Using Explicit Resolvers

Explicit resolvers are a powerful feature in gqlgen that allows you to customize the behavior of your resolvers. You can mark a field as requiring a resolver explicitly in the `gqlgen.yml` file.

Credit: youtube.com, 7.1 Write Custom GraphQL Resolvers

If you want to keep using the generated model, mark the field as requiring a resolver explicitly in `gqlgen.yml` like this:

```yaml

fields:

friends:

resolvers:

- explicit_resolver

```

This will force gqlgen to use the explicit resolver for the `friends` field.

You can also use inline config with directives to achieve the same result. The field resolvers will be executed concurrently in separate goroutines. The degree of concurrency can be customized with the `worker_limit` configuration attribute.

Yes! You can by remapping it in config as seen below:

```yaml

config:

worker_limit: 5

```

This will set the concurrency limit to 5.

Troubleshooting

If you're encountering errors with your GoLang GraphQL schema, it might be due to invalid input types. Ensure you're using the correct types for your schema.

One common issue is with the use of non-nullable types. If you're using a non-nullable type and the field is not provided in the input, it will result in an error.

To resolve this, consider using the `graphql.DefaultScalar` type for non-nullable fields. This allows for a default value to be used when the field is not provided.

Credit: youtube.com, What Could Go Wrong with a GraphQL Query & Can OpenTelemetry Help?

Another potential issue is with the use of custom scalars. If you're using a custom scalar, ensure it's properly registered with the GraphQL schema. Failure to do so will result in an error.

In some cases, you might encounter errors due to circular references in your schema. To resolve this, consider using the `graphql.Skip` function to skip certain fields or types.

Wm Kling

Lead Writer

Wm Kling is a seasoned writer with a passion for technology and innovation. With a strong background in software development, Wm brings a unique perspective to his writing, making complex topics accessible to a wide range of readers. Wm's expertise spans the realm of Visual Studio web development, where he has written in-depth articles and guides to help developers navigate the latest tools and technologies.

Love What You Read? Stay Updated!

Join our community for insights, tips, and more.