Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 11 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
_This package brought to you by [Adventure
Scientists](https://adventurescientists.org). Read more about [our open source
policy here](https://siliconally.org/policies/open-source/)._
_This package was developed by [Silicon Ally](https://siliconally.org) while
working on a project for [Adventure Scientists](https://adventurescientists.org).
Many thanks to Adventure Scientists for supporting [our open source
mission](https://siliconally.org/policies/open-source/)!_

| :warning: WARNING |
|:--------------------------------------------------|
| `rules_gqlgen` is experimental, use with caution. |

# rules_gqlgen

`rules_gqlgen` provides Bazel rules for working with the
`rules_gqlgen` provides **[bazel](https://bazel.build/) rules** that allow you to
build [GraphQL](https://graphql.org/) in [GoLang](https://go.dev/).

Under the hood, it generates a GoLang runtime + model using the
[gqlgen](https://github.com/99designs/gqlgen) GraphQL server + codegen library.

## Usage

```bazel
# In a BUILD.bazel
# In a BUILD.bazel file

load("@com_siliconally_rules_gqlgen//gqlgen:def.bzl", "gqlgen")

# The below rule generated two library targets, :gql_generated and :gql_model,
# The rule below generates two library targets, :gql_generated and :gql_model,
# which correspond to the auto-generated GraphQL glue code and model schema
# types respectively.
# The two generated rules would have import paths of
Expand All @@ -41,20 +45,4 @@ The `example` directory provides a basic GraphQL schema and server backed by
bazel run //example
```

The server will run on port 8080, you can access the playground at
`http://localhost:8080/api/playground`, and try requests like:

```graphql
# Query greetings
{
greetings {
message
lang
}
}

# Set a name
mutation {
updateName(req:{name:"Moxie"})
}
```
See the the example's README.md for a thorough explanation of what is happening.
102 changes: 102 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Example Usage

This minimal example demonstrates the functionality of this build rule.

To run this you'll need to have [bazel](https://bazel.build/) installed,
and it's also recommended to use [bazelisk](https://github.com/bazelbuild/bazelisk)
to choose a suitable version of bazel to run. We use [gazelle](https://github.com/bazelbuild/bazel-gazelle)
to manage GoLang dependencies in bazel, but that isn't strictly nescessary.

## What is happening?

The input to the build rule is the `schema.graphqls` - a file that describes
the queries and mutations that your GraphQL server is going to offer to clients.

When you run `bazel build`, this file is taken in, synthesized by a library called
`[gqlgen](https://github.com/99designs/gqlgen)`, and produces two pieces of
GoLang code.

In the first one, `bazel-bin/example/graph/model/models_gen.go`, the library
has created GoLang package called `model` which contains structs that mirror the
types expressed in your GraphQL schema. This allows you to write business logic
that uses types defined in your schema.

```golang
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.

package model

type Greeting struct {
Message string `json:"message"`
Lang string `json:"lang"`
}

type UpdateGreetingRequest struct {
Name string `json:"name"`
}
```

In order to actually implement the business logic of your GraphQL schema, you need
to implement __resolvers__ (GoLang functions that each implement a single
mutation or query in your GQL schema). In `main.go`, this is accomplished by creating
structs which implement these methods. Note how these methods correspond to the
mutations and queries expressed in the schema, and how the types used for inputs/outputs
come from the generated `model` pakage.

```
func (r *queryResolver) Greetings(ctx context.Context) ([]*model.Greeting, error) {
// ...
}

func (r *mutationResolver) UpdateName(ctx context.Context, req model.UpdateGreetingRequest) (*bool, error) {
//
}
```

The second output of this build rule can be found in `bazel-bin/example/graph/generated/generated.go`.
It is a generated server runtime in Golang that serves HTTP endpoints that (after layers of validation)
call the resolvers that you've defined. This server can be then be started (using the generated code and
your resolvers to service GraphQL requests over HTTP) by instantiating the server, and passing in the
resolvers, which tell the server how to execute your business logic.

```
import (
"github.com/99designs/gqlgen/graphql/handler"
"github.com/Silicon-Ally/rules_gqlgen/example/generated"
)

...
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}}))
...
```

## Playground

When you actually run the generated server, it runs on runs on port 8080, and you can access the playground at
`http://localhost:8080/api/playground`.

```graphql
# Query greetings
{
greetings {
message
lang
}
}

# Set a name
mutation {
updateName(req:{name:"Moxie"})
}
```

## Tweaking Configuration

You can modify the configuration passed to `gqlgen` by creating a `gqlgen.yml` and passing
it to the rule.

## Further Reading

This library (`rules_gqlgen`) enables this whole compilation and generation process to happen via
Bazel. The meat of the library is contained in the `[gqlgen](https://github.com/99designs/gqlgen)` library.
Their documentation contains lots of information on how to tweak your configuration + settings.
2 changes: 1 addition & 1 deletion gqlgen/generate.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
set -euxo pipefail

# Give our input arguments more semantic names, see gqlgen.bzl for more info.
# Give our input arguments more semantic names, see def.bzl for more info.
CONFIG="$1"
OUT_GEN_FILE="$(realpath "$2")"
OUT_MODELS_FILE="$(realpath "$3")"
Expand Down