Skip to content

Commit

Permalink
Merge pull request #416 from 99designs/improved-getting-started
Browse files Browse the repository at this point in the history
Improve Getting Started Documentation — No Binary Approach
  • Loading branch information
Mathew Byrne authored Nov 28, 2018
2 parents 6a02657 + 878f394 commit d6d9885
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 75 deletions.
3 changes: 3 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/internal/gopath"
"github.com/urfave/cli"

// Required since otherwise dep will prune away these unused packages before codegen has a chance to run
_ "github.com/99designs/gqlgen/handler"
)

func Execute() {
Expand Down
2 changes: 1 addition & 1 deletion codegen/templates/data.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions codegen/templates/resolver.gotpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:generate gorunpkg github.com/99designs/gqlgen

package {{ .PackageName }}

import (
Expand Down
2 changes: 0 additions & 2 deletions codegen/testserver/resolver.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:generate gorunpkg github.com/99designs/gqlgen

package testserver

import (
Expand Down
133 changes: 73 additions & 60 deletions docs/content/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,60 @@
---
linkTitle: Getting Started
title: Building graphql servers in golang
description: Get started building type-safe graphql servers in Golang using gqlgen
title: Building GraphQL servers in golang
description: Get started building type-safe GraphQL servers in Golang using gqlgen
menu: main
weight: -5
---

## Goal
This tutorial will take you through the process of building a GraphQL server with gqlgen that can:

The aim for this tutorial is to build a "todo" graphql server that can:

- get a list of all todos
- create new todos
- mark off todos as they are completed
- Return a list of todos
- Create new todos
- Mark off todos as they are completed

You can find the finished code for this tutorial [here](https://github.com/vektah/gqlgen-tutorials/tree/master/gettingstarted)

## Install gqlgen

Assuming you already have a working [go environment](https://golang.org/doc/install) you can simply go get:
This article uses [`dep`](https://github.com/golang/dep) to install gqlgen. [Follow the instructions for your environment](https://github.com/golang/dep) to install.

Assuming you already have a working [Go environment](https://golang.org/doc/install), create a directory for the project in your `$GOPATH`:

```sh
$ mkdir -p $GOPATH/src/github.com/[username]/gqlgen-todos
```

> Go Modules
>
> Currently `gqlgen` does not support Go Modules. This is due to the [`loader`](https://godoc.org/golang.org/x/tools/go/loader) package, that also does not yet support Go Modules. We are looking at solutions to this and the issue is tracked in Github.
Add the following file to your project under `scripts/gqlgen.go`:

```go
// +build ignore

package main

import "github.com/99designs/gqlgen/cmd"

func main() {
cmd.Execute()
}
```

Lastly, initialise dep. This will inspect any imports you have in your project, and pull down the latest tagged release.

```sh
go get -u github.com/99designs/gqlgen github.com/vektah/gorunpkg
$ dep init
```

## Building the server

### Define the schema

gqlgen is a schema-first library, so before touching any code we write out the API we want using the graphql
[Schema Definition Language](http://graphql.org/learn/schema/). This usually goes into a file called schema.graphql
gqlgen is a schema-first library before writing code, you describe your API using the GraphQL
[Schema Definition Language](http://graphql.org/learn/schema/). This usually goes into a file called `schema.graphql`:

`schema.graphql`
```graphql
type Todo {
id: ID!
Expand Down Expand Up @@ -60,23 +83,29 @@ type Mutation {
```

### Create the project skeleton

```bash
$ gqlgen init
Exec "go run ./server/server.go" to start GraphQL server
$ go run scripts/gqlgen.go init
```

This has created an empty skeleton with all files we need:
This has created an empty skeleton with all files you need:

- `gqlgen.yml` — The gqlgen config file, knobs for controlling the generated code.
- `generated.go` — The GraphQL execution runtime, the bulk of the generated code.
- `models_gen.go` — Generated models required to build the graph. Often you will override these with your own models. Still very useful for input types.
- `resolver.go` — This is where your application code lives. `generated.go` will call into this to get the data the user has requested.
- `server/server.go` — This is a minimal entry point that sets up an `http.Handler` to the generated GraphQL server.

Now run dep ensure, so that we can ensure that the newly generated code's dependencies are all present:

- gqlgen.yml - The gqlgen config file, knobs for controlling the generated code.
- generated.go - The graphql execution runtime, the bulk of the generated code
- models_gen.go - Generated models required to build the graph. Often you will override these with models you write yourself. Still very useful for input types.
- resolver.go - This is where your application code lives. generated.go will call into this to get the data the user has requested.
```sh
$ dep ensure
```

### Create the database models

The generated model for Todo isnt quite right, it has a user embeded in it but we only want to fetch it if the user actually requested it. So lets make our own.
The generated model for Todo isn't right, it has a user embeded in it but we only want to fetch it if the user actually requested it. So instead lets make a new model in `todo.go`:

`todo.go`
```go
package gettingstarted
Expand All @@ -88,22 +117,27 @@ type Todo struct {
}
```

And then tell gqlgen to use this new struct by adding this to the gqlgen.yml:
Next tell gqlgen to use this new struct by adding it to `gqlgen.yml`:

```yaml
models:
Todo:
model: github.com/vektah/gqlgen-tutorials/gettingstarted.Todo
model: github.com/[username]/gqlgen-todos/gettingstarted.Todo
```

and regenerate by running
Regenerate by running:

```bash
$ gqlgen -v
Unable to bind Todo.user to github.com/vektah/gqlgen-tutorials/gettingstarted.Todo
$ go run scripts/gqlgen.go -v
Unable to bind Todo.user to github.com/[username]/gqlgen-todos/gettingstarted.Todo
no method named user
no field named user
Adding resolver method
```
*note* we've used the verbose flag here to show what gqlgen is doing. Its looked at all the fields on our model and found matching methods for all of them, except user. For user it added a resolver to the interface we need to implement. This is the magic that makes gqlgen work so well.

> Note
>
> The verbose flag `-v` is here to show what gqlgen is doing. It has looked at all the fields on the model and found matching methods for all of them, except user. For user it has added a resolver to the interface you need to implement. *This is the magic that makes gqlgen work so well!*

### Implement the resolvers

Expand Down Expand Up @@ -151,18 +185,17 @@ better than generating.

### Write the resolvers

This is a work in progress, we have a way to generate resolver stubs, but it cannot currently update existing code. We can force it to run again by deleting `resolvers.go` and re-running gqlgen:
This is a work in progress, we have a way to generate resolver stubs, but it cannot currently update existing code. We can force it to run again by deleting `resolver.go` and re-running gqlgen:

```bash
rm resolvers.go
gqlgen
$ rm resolver.go
$ go run scripts/gqlgen.go
```

Now we just need to fill in the `not implemented` parts

Now we just need to fill in the `not implemented` parts. Update `graph/graph.go`

`graph/graph.go`
```go
//go:generate gorunpkg github.com/99designs/gqlgen
//go:generate go run ./scripts/gqlgen.go
package gettingstarted
Expand Down Expand Up @@ -242,34 +275,14 @@ query findTodos {
## Finishing touches
gqlgen is still unstable, and the APIs may change at any time. To prevent changes from ruining your day make sure
to lock your dependencies:

*Note*: If you dont have dep installed yet, you can get it [here](https://github.com/golang/dep)

First uninstall the global version we grabbed earlier. This is a good way to prevent version mismatch footguns.

```bash
rm ~/go/bin/gqlgen
rm -rf ~/go/src/github.com/99designs/gqlgen
```
At the top of our `resolver.go` add the following line:
Next install gorunpkg, its kind of like npx but only searches vendor.

```bash
dep init
dep ensure
```

At the top of our resolvers.go a go generate command was added that looks like this:
```go
//go:generate gorunpkg github.com/99designs/gqlgen
//go:generate go run scripts/gqlgen.go -v
```
This magic comment tells `go generate` what command to run when we want to regenerate our code. to do so run:
This magic comment tells `go generate` what command to run when we want to regenerate our code. To run go generate recursively over your entire project, use this command:
```go
go generate ./...
```

*gorunpkg* will build and run the version of gqlgen we just installed into vendor with dep. This makes sure that everyone working on your project generates code the same way regardless which binaries are installed in their gopath.

```
Loading

0 comments on commit d6d9885

Please sign in to comment.