github.com/roneli/gqlgen@v0.7.2/docs/content/getting-started.md (about)

     1  ---
     2  linkTitle: Getting Started
     3  title: Building GraphQL servers in golang
     4  description: Get started building type-safe GraphQL servers in Golang using gqlgen  
     5  menu: main
     6  weight: -5
     7  ---
     8  
     9  This tutorial will take you through the process of building a GraphQL server with gqlgen that can:
    10  
    11   - Return a list of todos
    12   - Create new todos
    13   - Mark off todos as they are completed
    14  
    15  You can find the finished code for this tutorial [here](https://github.com/vektah/gqlgen-tutorials/tree/master/gettingstarted)
    16  
    17  ## Install gqlgen
    18  
    19  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.
    20  
    21  Assuming you already have a working [Go environment](https://golang.org/doc/install), create a directory for the project in your `$GOPATH`:
    22  
    23  ```sh
    24  $ mkdir -p $GOPATH/src/github.com/[username]/gqlgen-todos
    25  ```
    26  
    27  > Go Modules
    28  >
    29  > 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.
    30  
    31  Add the following file to your project under `scripts/gqlgen.go`:
    32  
    33  ```go
    34  // +build ignore
    35  
    36  package main
    37  
    38  import "github.com/99designs/gqlgen/cmd"
    39  
    40  func main() {
    41  	cmd.Execute()
    42  }
    43  ```
    44  
    45  Lastly, initialise dep.  This will inspect any imports you have in your project, and pull down the latest tagged release.
    46  
    47  ```sh
    48  $ dep init
    49  ```
    50  
    51  ## Building the server
    52  
    53  ### Define the schema
    54  
    55  gqlgen is a schema-first library — before writing code, you describe your API using the GraphQL 
    56  [Schema Definition Language](http://graphql.org/learn/schema/). This usually goes into a file called `schema.graphql`:
    57  
    58  ```graphql
    59  type Todo {
    60    id: ID!
    61    text: String!
    62    done: Boolean!
    63    user: User!
    64  }
    65  
    66  type User {
    67    id: ID!
    68    name: String!
    69  }
    70  
    71  type Query {
    72    todos: [Todo!]!
    73  }
    74  
    75  input NewTodo {
    76    text: String!
    77    userId: String!
    78  }
    79  
    80  type Mutation {
    81    createTodo(input: NewTodo!): Todo!
    82  }
    83  ```
    84  
    85  ### Create the project skeleton
    86  
    87  ```bash
    88  $ go run scripts/gqlgen.go init
    89  ```
    90  
    91  This has created an empty skeleton with all files you need:
    92  
    93   - `gqlgen.yml` — The gqlgen config file, knobs for controlling the generated code.
    94   - `generated.go` — The GraphQL execution runtime, the bulk of the generated code.
    95   - `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.
    96   - `resolver.go` — This is where your application code lives. `generated.go` will call into this to get the data the user has requested. 
    97   - `server/server.go` — This is a minimal entry point that sets up an `http.Handler` to the generated GraphQL server.
    98  
    99   Now run dep ensure, so that we can ensure that the newly generated code's dependencies are all present:
   100  
   101   ```sh
   102   $ dep ensure
   103   ```
   104   
   105  ### Create the database models
   106  
   107  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`:
   108  
   109  ```go
   110  package gettingstarted
   111  
   112  type Todo struct {
   113  	ID     string
   114  	Text   string
   115  	Done   bool
   116  	UserID string
   117  }
   118  ```
   119  
   120  Next tell gqlgen to use this new struct by adding it to `gqlgen.yml`:
   121  
   122  ```yaml
   123  models:
   124    Todo:
   125      model: github.com/[username]/gqlgen-todos/gettingstarted.Todo
   126  ```
   127  
   128  Regenerate by running:
   129  
   130  ```bash
   131  $ go run scripts/gqlgen.go -v
   132  Unable to bind Todo.user to github.com/[username]/gqlgen-todos/gettingstarted.Todo
   133  	no method named user
   134  	no field named user
   135  	Adding resolver method
   136  ```
   137  
   138  > Note
   139  >
   140  > 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!*
   141  
   142  ### Implement the resolvers
   143  
   144  The generated runtime has defined an interface for all the missing resolvers that we need to provide. Lets take a look in `generated.go`
   145  
   146  ```go
   147  // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
   148  func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
   149  	return &executableSchema{
   150  		resolvers:  cfg.Resolvers,
   151  		directives: cfg.Directives,
   152  	}
   153  }
   154  
   155  type Config struct {
   156  	Resolvers  ResolverRoot
   157  	Directives DirectiveRoot
   158  }
   159  
   160  type ResolverRoot interface {
   161  	Mutation() MutationResolver
   162  	Query() QueryResolver
   163  	Todo() TodoResolver
   164  }
   165  
   166  type DirectiveRoot struct {
   167  }
   168  type MutationResolver interface {
   169  	CreateTodo(ctx context.Context, input NewTodo) (Todo, error)
   170  }
   171  type QueryResolver interface {
   172  	Todos(ctx context.Context) ([]Todo, error)
   173  }
   174  type TodoResolver interface {
   175  	User(ctx context.Context, obj *Todo) (User, error)
   176  }
   177  ```
   178  
   179  Notice the `TodoResolver.User` method? Thats gqlgen saying "I dont know how to get a User from a Todo, you tell me.".
   180  Its worked out how to build everything else for us.
   181  
   182  For any missing models (like NewTodo) gqlgen will generate a go struct. This is usually only used for input types and 
   183  one-off return values. Most of the time your types will be coming from the database, or an API client so binding is
   184  better than generating.
   185  
   186  ### Write the resolvers
   187  
   188  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:
   189  
   190  ```bash
   191  $ rm resolver.go
   192  $ go run scripts/gqlgen.go
   193  ```
   194  
   195  Now we just need to fill in the `not implemented` parts.  Update `resolver.go`
   196  
   197  ```go
   198  //go:generate go run ./scripts/gqlgen.go
   199  
   200  package gettingstarted
   201  
   202  import (
   203  	context "context"
   204  	"fmt"
   205  	"math/rand"
   206  )
   207  
   208  type Resolver struct{
   209  	todos []Todo
   210  }
   211  
   212  func (r *Resolver) Mutation() MutationResolver {
   213  	return &mutationResolver{r}
   214  }
   215  func (r *Resolver) Query() QueryResolver {
   216  	return &queryResolver{r}
   217  }
   218  func (r *Resolver) Todo() TodoResolver {
   219  	return &todoResolver{r}
   220  }
   221  
   222  type mutationResolver struct{ *Resolver }
   223  
   224  func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (Todo, error) {
   225  	todo := Todo{
   226  		Text:   input.Text,
   227  		ID:     fmt.Sprintf("T%d", rand.Int()),
   228  		UserID: input.UserID,
   229  	}
   230  	r.todos = append(r.todos, todo)
   231  	return todo, nil
   232  }
   233  
   234  type queryResolver struct{ *Resolver }
   235  
   236  func (r *queryResolver) Todos(ctx context.Context) ([]Todo, error) {
   237  	return r.todos, nil
   238  }
   239  
   240  type todoResolver struct{ *Resolver }
   241  
   242  func (r *todoResolver) User(ctx context.Context, obj *Todo) (User, error) {
   243  	return User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
   244  }
   245  
   246  ```
   247  
   248  We now have a working server, to start it:
   249  ```bash
   250  go run server/server.go
   251  ```
   252  
   253  then open http://localhost:8080 in a browser. here are some queries to try:
   254  ```graphql
   255  mutation createTodo {
   256    createTodo(input:{text:"todo", userId:"1"}) {
   257      user {
   258        id
   259      }
   260      text
   261      done
   262    }
   263  }
   264  
   265  query findTodos {
   266    	todos {
   267        text
   268        done
   269        user {
   270          name
   271        }
   272      }
   273  }
   274  ```
   275  
   276  ## Finishing touches
   277  
   278  At the top of our `resolver.go` add the following line:
   279  
   280  ```go
   281  //go:generate go run scripts/gqlgen.go -v
   282  ```
   283  
   284  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:
   285  
   286  ```go
   287  go generate ./...
   288  ```
   289  
   290  > Note
   291  >
   292  > Ensure that the path to your `gqlgen` binary is relative to the file the generate command is added to.