Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
example/
7 changes: 6 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ jobs:
path: "~/.cache/bazel"
key: bazel

- run: bazel build //...
- name: Build rules_gqlgen
run: bazel build //...

- name: Build example server
working-directory: ./example
run: bazel build //...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ bazel-bin
bazel-out
bazel-testlogs
bazel-rules_gqlgen
bazel-example
2 changes: 0 additions & 2 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
load("@bazel_gazelle//:def.bzl", "gazelle")

# gazelle:prefix github.com/Silicon-Ally/rules_gqlgen
# gazelle:resolve go github.com/Silicon-Ally/rules_gqlgen/example/generated //example:gql_generated
# gazelle:resolve go github.com/Silicon-Ally/rules_gqlgen/example/model //example:gql_model
gazelle(name = "gazelle")

gazelle(
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,18 @@ The `example` directory provides a basic GraphQL schema and server backed by
`gqlgen`, you can run it with:

```bash
bazel run //example
# example/ is a separate Bazel workspace, so need to enter it first.
cd example
# Run the server on port 8080
bazel run //:example
```

See the the example's README.md for a thorough explanation of what is happening.
See the the [example's README.md](/example/README.md) for a thorough
explanation of what is happening.

## Modifying gqlgen.yml

Currently, `rules_gqlgen` does not support the gqlgen configuration file,
`gqlgen.yml` file, beyond specifying the schema to generate code for. If this
is important to you, or you have specific features in mind that you'd like
supported, file an issue.
4 changes: 2 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ http_archive(

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
load("//:deps.bzl", "go_dependencies")
load("//:deps.bzl", "gqlgen_dependencies")

# gazelle:repository_macro deps.bzl%go_dependencies
go_dependencies()
gqlgen_dependencies()

go_rules_dependencies()

Expand Down
48 changes: 31 additions & 17 deletions deps.bzl
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
load("@bazel_gazelle//:deps.bzl", "go_repository")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load(
"@bazel_gazelle//:deps.bzl",
_go_repository = "go_repository",
)

def go_repository(**kwargs):
_maybe(_go_repository, **kwargs)

def gqlgen_dependencies():
go_dependencies()

def go_dependencies():
go_repository(
name = "com_github_99designs_gqlgen",
importpath = "github.com/99designs/gqlgen",
sum = "h1:lH/H5dTYCY5eLNRKXeq22l0wFMavpOnN6v9GAIw+fxY=",
version = "v0.17.12",
sum = "h1:ETUEqvRg5Zvr1lXtpoRdj026fzVay0ZlJPwI33qXLIw=",
version = "v0.17.13",
)
go_repository(
name = "com_github_agnivade_levenshtein",
Expand Down Expand Up @@ -34,8 +44,8 @@ def go_dependencies():
go_repository(
name = "com_github_cpuguy83_go_md2man_v2",
importpath = "github.com/cpuguy83/go-md2man/v2",
sum = "h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=",
version = "v2.0.2",
sum = "h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=",
version = "v2.0.1",
)
go_repository(
name = "com_github_davecgh_go_spew",
Expand Down Expand Up @@ -125,8 +135,8 @@ def go_dependencies():
go_repository(
name = "com_github_mitchellh_mapstructure",
importpath = "github.com/mitchellh/mapstructure",
sum = "h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=",
version = "v1.3.1",
sum = "h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=",
version = "v1.5.0",
)
go_repository(
name = "com_github_pmezard_go_difflib",
Expand Down Expand Up @@ -162,14 +172,14 @@ def go_dependencies():
go_repository(
name = "com_github_urfave_cli_v2",
importpath = "github.com/urfave/cli/v2",
sum = "h1:c6bD90aLd2iEsokxhxkY5Er0zA2V9fId2aJfwmrF+do=",
version = "v2.11.0",
sum = "h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4=",
version = "v2.8.1",
)
go_repository(
name = "com_github_vektah_gqlparser_v2",
importpath = "github.com/vektah/gqlparser/v2",
sum = "h1:Yjzp66g6oVq93Jihbi0qhGnf/6zIWjcm8H6gA27zstE=",
version = "v2.4.6",
sum = "h1:yub2WLoSIr+chP1zMv6bjrsgTasfubxGZJeC8ISEpgE=",
version = "v2.4.7",
)
go_repository(
name = "com_github_xrash_smetrics",
Expand Down Expand Up @@ -235,8 +245,8 @@ def go_dependencies():
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
sum = "h1:/m5NbqQelATgoSPVC2Z23sR4kVNokFwDDyWh/3rGY+I=",
version = "v0.0.0-20220708085239-5a0f0661e09d",
sum = "h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=",
version = "v0.0.0-20211019181941-9d821ace8654",
)
go_repository(
name = "org_golang_x_term",
Expand All @@ -253,12 +263,16 @@ def go_dependencies():
go_repository(
name = "org_golang_x_tools",
importpath = "golang.org/x/tools",
sum = "h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=",
version = "v0.1.11",
sum = "h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=",
version = "v0.1.10",
)
go_repository(
name = "org_golang_x_xerrors",
importpath = "golang.org/x/xerrors",
sum = "h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=",
version = "v0.0.0-20220609144429-65e65417b02f",
sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=",
version = "v0.0.0-20200804184101-5ec99f83aff1",
)

def _maybe(repo_rule, name, **kwargs):
if name not in native.existing_rules():
repo_rule(name = name, **kwargs)
1 change: 1 addition & 0 deletions example/.bazelversion
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5.1.0
32 changes: 28 additions & 4 deletions example/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("//gqlgen:def.bzl", "gqlgen")
load("@rules_gqlgen//gqlgen:def.bzl", "gqlgen")
load("@bazel_gazelle//:def.bzl", "gazelle")

# gazelle:prefix github.com/Silicon-Ally/rules_gqlgen/example
# gazelle:resolve go github.com/Silicon-Ally/rules_gqlgen/example/generated //gql_generated
# gazelle:resolve go github.com/Silicon-Ally/rules_gqlgen/example/model //gql_model
gazelle(name = "gazelle")

gazelle(
name = "gazelle-update-repos",
args = [
"-from_file=go.mod",
"-to_macro=deps.bzl%go_dependencies",
"-prune",
],
command = "update-repos",
)

gqlgen(
name = "gql",
base_importpath = "github.com/Silicon-Ally/rules_gqlgen/example",
schemas = [":schema.graphqls"],
schemas = ["//:schema.graphqls"],
visibility = ["//visibility:public"],
gomod = "//:go.mod",
gosum = "//:go.sum",
Expand All @@ -16,8 +32,8 @@ go_library(
importpath = "github.com/Silicon-Ally/rules_gqlgen/example",
visibility = ["//visibility:private"],
deps = [
"//example:gql_generated",
"//example:gql_model",
"//:gql_generated",
"//:gql_model",
"@com_github_99designs_gqlgen//graphql/handler",
"@com_github_99designs_gqlgen//graphql/playground",
],
Expand All @@ -28,3 +44,11 @@ go_binary(
embed = [":example_lib"],
visibility = ["//visibility:public"],
)

exports_files([
"go.mod",
"go.sum",
])

exports_files(["schema.graphqls"])

77 changes: 34 additions & 43 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Example Usage

This minimal example demonstrates the functionality of this build rule.
This minimal example demonstrates the functionality of the `gqlgen` 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 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 Go 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.
The input to the build rule is the `schema.graphqls`, which describes the
queries and mutations that your GraphQL server is going to serve to clients.
The format of the GraphQL schema file is described in
[the official GraphQL docs](https://graphql.org/learn/).

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.
When the rule executes, a [gqlgen.yml](https://gqlgen.com/config/) file is generated, the `gqlgen` code generator tool is run, and two
separate Go libraries are produced, `model` and `generated`.

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.
The `model` library consists of `bazel-bin/example/model/models_gen.go`, which
contains the Go 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.
Expand All @@ -36,44 +36,45 @@ type UpdateGreetingRequest struct {
}
```

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.
The `generated` library consists of `bazel-bin/example/generated/generated.go`,
which contains a generated GraphQL server runtime that can serve your API,
usually over HTTP and/or WebSockets. It handles deserializing and validating
the incoming requests, then calling the correct resolvers, which you'll
implement. For this example, the interface to implement looks like:

```
func (r *queryResolver) Greetings(ctx context.Context) ([]*model.Greeting, error) {
// ...
```go
type ResolverRoot interface {
Mutation() MutationResolver
Query() QueryResolver
}

func (r *mutationResolver) UpdateName(ctx context.Context, req model.UpdateGreetingRequest) (*bool, error) {
//
type MutationResolver interface {
UpdateName(ctx context.Context, req model.UpdateGreetingRequest) (*bool, error)
}
type QueryResolver interface {
Greetings(ctx context.Context) ([]*model.Greeting, 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.
Take a look at [main.go](/example/main.go) to see what a basic `Resolver`
implementation looks like. Then, you can instantiate your server like:

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

...
// ... more setup code ...
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}}))
...
// ... srv implements http.Handler and can now be used, e.g. via http.ListenAndServe ...
```

## Playground

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

```graphql
# Query greetings
Expand All @@ -89,13 +90,3 @@ mutation {
updateName(req:{name:"Moxie"})
}
```

## Tweaking Configuration

Today, you cannot tweak the GQL configuration via a `gqlgen.yml` file (as you can via a vanilla `gqlgen` integration). If this is important to you, or you have specific flags/features in mind that you'd like to contribute, shoot us an email/file a Github Issue.

## 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.
39 changes: 39 additions & 0 deletions example/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
name = "io_bazel_rules_go",
sha256 = "685052b498b6ddfe562ca7a97736741d87916fe536623afb7da2824c0211c369",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.33.0/rules_go-v0.33.0.zip",
],
)

http_archive(
name = "bazel_gazelle",
sha256 = "501deb3d5695ab658e82f6f6f549ba681ea3ca2a5fb7911154b5aa45596183fa",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.26.0/bazel-gazelle-v0.26.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.26.0/bazel-gazelle-v0.26.0.tar.gz",
],
)

# In a non-example project, this would usually be imported with http_archive or
# similar, see the rules_gqlgen release notes for more details.
local_repository(
name="rules_gqlgen",
path= "..",
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
load("@rules_gqlgen//:deps.bzl", "gqlgen_dependencies")
load("//:deps.bzl", "go_dependencies")

# gazelle:repository_macro deps.bzl%go_dependencies
go_dependencies()

gqlgen_dependencies()
go_rules_dependencies()
go_register_toolchains(version = "1.19")
gazelle_dependencies()
Loading