github.com/bewolv/gqlgen@v0.10.12/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: -7 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 > Note 18 > 19 > This tutorial uses Go Modules and requires Go 1.11+. If you want to use this tutorial without Go Modules, take a look at our [Getting Started Using dep]({{< ref "getting-started-dep.md" >}}) guide instead. 20 21 ## Setup Project 22 23 Create a directory for your project, and initialise it as a Go Module: 24 25 ```sh 26 $ mkdir gqlgen-todos 27 $ cd gqlgen-todos 28 $ go mod init github.com/[username]/gqlgen-todos 29 ``` 30 31 ## Building the server 32 33 ### Define the schema 34 35 gqlgen is a schema-first library — before writing code, you describe your API using the GraphQL 36 [Schema Definition Language](http://graphql.org/learn/schema/). This usually goes into a file called `schema.graphql`. A basic example as follows will be generated by the `init` command: 37 38 ```graphql 39 type Todo { 40 id: ID! 41 text: String! 42 done: Boolean! 43 user: User! 44 } 45 46 type User { 47 id: ID! 48 name: String! 49 } 50 51 type Query { 52 todos: [Todo!]! 53 } 54 55 input NewTodo { 56 text: String! 57 userId: String! 58 } 59 60 type Mutation { 61 createTodo(input: NewTodo!): Todo! 62 } 63 ``` 64 65 ### Create the project skeleton 66 67 ```bash 68 $ go run github.com/bewolv/gqlgen init 69 ``` 70 71 This has created an empty skeleton with all files you need: 72 73 - `gqlgen.yml` — The gqlgen config file, knobs for controlling the generated code. 74 - `generated.go` — The GraphQL execution runtime, the bulk of the generated code. 75 - `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. 76 - `resolver.go` — This is where your application code lives. `generated.go` will call into this to get the data the user has requested. 77 - `server/server.go` — This is a minimal entry point that sets up an `http.Handler` to the generated GraphQL server. 78 79 ### Create the database models 80 81 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`: 82 83 ```go 84 package gqlgen_todos 85 86 type Todo struct { 87 ID string 88 Text string 89 Done bool 90 UserID string 91 } 92 ``` 93 94 Next tell gqlgen to use this new struct by adding it to `gqlgen.yml`: 95 96 ```yaml 97 models: 98 Todo: 99 model: github.com/[username]/gqlgen-todos.Todo 100 ``` 101 102 Regenerate by running: 103 104 ```bash 105 $ go run github.com/bewolv/gqlgen -v 106 ``` 107 108 > Note 109 > 110 > 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!* 111 112 ### Implement the resolvers 113 114 The generated runtime has defined an interface for all the missing resolvers that we need to provide. Lets take a look in `generated.go`: 115 116 ```go 117 func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {} 118 // ... 119 } 120 121 type Config struct { 122 Resolvers ResolverRoot 123 // ... 124 } 125 126 type ResolverRoot interface { 127 Mutation() MutationResolver 128 Query() QueryResolver 129 Todo() TodoResolver 130 } 131 132 type MutationResolver interface { 133 CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) 134 } 135 type QueryResolver interface { 136 Todos(ctx context.Context) ([]Todo, error) 137 } 138 type TodoResolver interface { 139 User(ctx context.Context, obj *Todo) (*User, error) 140 } 141 ``` 142 143 Notice the `TodoResolver.User` method? Thats gqlgen saying "I dont know how to get a User from a Todo, you tell me.". 144 Its worked out how to build everything else for us. 145 146 For any missing models (like `NewTodo`) gqlgen will generate a go struct. This is usually only used for input types and 147 one-off return values. Most of the time your types will be coming from the database, or an API client so binding is 148 better than generating. 149 150 ### Write the resolvers 151 152 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: 153 154 ```bash 155 $ rm resolver.go 156 $ go run github.com/bewolv/gqlgen 157 ``` 158 159 Now we just need to fill in the `not implemented` parts. Update `resolver.go` 160 161 ```go 162 package gqlgen_todos 163 164 import ( 165 context "context" 166 "fmt" 167 "math/rand" 168 ) 169 170 type Resolver struct { 171 todos []*Todo 172 } 173 174 func (r *Resolver) Mutation() MutationResolver { 175 return &mutationResolver{r} 176 } 177 func (r *Resolver) Query() QueryResolver { 178 return &queryResolver{r} 179 } 180 func (r *Resolver) Todo() TodoResolver { 181 return &todoResolver{r} 182 } 183 184 type mutationResolver struct{ *Resolver } 185 186 func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) { 187 todo := &Todo{ 188 Text: input.Text, 189 ID: fmt.Sprintf("T%d", rand.Int()), 190 UserID: input.UserID, 191 } 192 r.todos = append(r.todos, todo) 193 return todo, nil 194 } 195 196 type queryResolver struct{ *Resolver } 197 198 func (r *queryResolver) Todos(ctx context.Context) ([]*Todo, error) { 199 return r.todos, nil 200 } 201 202 type todoResolver struct{ *Resolver } 203 204 func (r *todoResolver) User(ctx context.Context, obj *Todo) (*User, error) { 205 return &User{ID: obj.UserID, Name: "user " + obj.UserID}, nil 206 } 207 208 ``` 209 210 We now have a working server, to start it: 211 ```bash 212 go run server/server.go 213 ``` 214 215 then open http://localhost:8080 in a browser. here are some queries to try: 216 ```graphql 217 mutation createTodo { 218 createTodo(input:{text:"todo", userId:"1"}) { 219 user { 220 id 221 } 222 text 223 done 224 } 225 } 226 227 query findTodos { 228 todos { 229 text 230 done 231 user { 232 name 233 } 234 } 235 } 236 ``` 237 238 ## Finishing touches 239 240 At the top of our `resolver.go`, between `package` and `import`, add the following line: 241 242 ```go 243 //go:generate go run github.com/bewolv/gqlgen 244 ``` 245 246 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: 247 248 ```go 249 go generate ./... 250 ```