Setup Project
使用 Go Module 記得先執行 export GO111MODULE=on
1
2
3
| mkdir gqlgen-todos
cd gqlgen-todos
go mod init github.com/[username]/gqlgen-todos
|
Define the schema
新增 schema.graphql
定義 graphql 結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| type Todo {
id: ID!
text: String!
done: Boolean!
user: User!
}
type User {
id: ID!
name: String!
}
type Query {
todos: [Todo!]!
}
input NewTodo {
text: String!
userId: String!
}
type Mutation {
createTodo(input: NewTodo!): Todo!
}
|
Create the project skeleton
透過 gglgen
建立 graphql 的專案初始化
1
| go run github.com/99designs/gqlgen init
|
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.
Create the database models
自動生成的 Todo model 不是正確的,因為 Todo 裡面還嵌入了 User,我們希望是在使用者要求時才給予,因此要另外建立 todo.go
1
2
3
4
5
6
7
8
9
| // todo.go
package gqlgen_todos
type Todo struct {
ID string
Text string
Done bool
UserID string
}
|
將新的 struct 路徑加到 gqlgen.yml
1
2
3
4
5
| // Todo 對應到 todo.go 裡的 struct name
models:
Todo:
model: github.com/[username]/gqlgen-todos.Todo
|
重新生成檔案
1
| go run github.com/99designs/gqlgen
|
Implement the resolvers
在 generated.go
產生了很多個 resolvers interface,接著就要實作這些,但 resolver.go
這個檔案,再新增新的 method 時,要重新再產生一份
1
2
| rm resolver.go
go run github.com/99designs/gqlgen
|
實作 resolver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| package gqlgen_todos
import (
context "context"
"fmt"
"math/rand"
)
type Resolver struct {
todos []Todo
}
func (r *Resolver) Mutation() MutationResolver {
return &mutationResolver{r}
}
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
}
func (r *Resolver) Todo() TodoResolver {
return &todoResolver{r}
}
type mutationResolver struct{ *Resolver }
func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) {
todo := &Todo{
Text: input.Text,
ID: fmt.Sprintf("T%d", rand.Int()),
UserID: input.UserID,
}
r.todos = append(r.todos, *todo)
return todo, nil
}
type queryResolver struct{ *Resolver }
func (r *queryResolver) Todos(ctx context.Context) ([]Todo, error) {
return r.todos, nil
}
type todoResolver struct{ *Resolver }
func (r *todoResolver) User(ctx context.Context, obj *Todo) (*User, error) {
return &User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
}
|
Query
1
2
| // open http://localhost:8080
go run server/server.go
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // create
mutation createTodo {
createTodo(input:{text:"todo", userId:"1"}) {
user {
id
}
text
done
}
}
// show
query findTodos {
todos {
text
done
user {
name
}
}
}
|
Finishing touches
At the top of our resolver.go add the following line:
1
| //go:generate go run github.com/99designs/gqlgen
|
This magic comment tells go generate what command to run when we want to regenerate our code
Example
Reference