Skip to content

Commit 05c348c

Browse files
authored
Merge pull request #574 from graphql-go/examples-todo-schema
examples/todo: extracts TodoSchema
2 parents d6b7434 + 279aceb commit 05c348c

File tree

2 files changed

+189
-180
lines changed

2 files changed

+189
-180
lines changed

examples/todo/main.go

Lines changed: 6 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -8,192 +8,18 @@ import (
88
"time"
99

1010
"github.com/graphql-go/graphql"
11+
"github.com/graphql-go/graphql/examples/todo/schema"
1112
)
1213

13-
type Todo struct {
14-
ID string `json:"id"`
15-
Text string `json:"text"`
16-
Done bool `json:"done"`
17-
}
18-
19-
var TodoList []Todo
20-
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
21-
22-
func RandStringRunes(n int) string {
23-
b := make([]rune, n)
24-
for i := range b {
25-
b[i] = letterRunes[rand.Intn(len(letterRunes))]
26-
}
27-
return string(b)
28-
}
29-
3014
func init() {
31-
todo1 := Todo{ID: "a", Text: "A todo not to forget", Done: false}
32-
todo2 := Todo{ID: "b", Text: "This is the most important", Done: false}
33-
todo3 := Todo{ID: "c", Text: "Please do this or else", Done: false}
34-
TodoList = append(TodoList, todo1, todo2, todo3)
15+
todo1 := schema.Todo{ID: "a", Text: "A todo not to forget", Done: false}
16+
todo2 := schema.Todo{ID: "b", Text: "This is the most important", Done: false}
17+
todo3 := schema.Todo{ID: "c", Text: "Please do this or else", Done: false}
18+
schema.TodoList = append(schema.TodoList, todo1, todo2, todo3)
3519

3620
rand.Seed(time.Now().UnixNano())
3721
}
3822

39-
// define custom GraphQL ObjectType `todoType` for our Golang struct `Todo`
40-
// Note that
41-
// - the fields in our todoType maps with the json tags for the fields in our struct
42-
// - the field type matches the field type in our struct
43-
var todoType = graphql.NewObject(graphql.ObjectConfig{
44-
Name: "Todo",
45-
Fields: graphql.Fields{
46-
"id": &graphql.Field{
47-
Type: graphql.String,
48-
},
49-
"text": &graphql.Field{
50-
Type: graphql.String,
51-
},
52-
"done": &graphql.Field{
53-
Type: graphql.Boolean,
54-
},
55-
},
56-
})
57-
58-
// root mutation
59-
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
60-
Name: "RootMutation",
61-
Fields: graphql.Fields{
62-
/*
63-
curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
64-
*/
65-
"createTodo": &graphql.Field{
66-
Type: todoType, // the return type for this field
67-
Description: "Create new todo",
68-
Args: graphql.FieldConfigArgument{
69-
"text": &graphql.ArgumentConfig{
70-
Type: graphql.NewNonNull(graphql.String),
71-
},
72-
},
73-
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
74-
75-
// marshall and cast the argument value
76-
text, _ := params.Args["text"].(string)
77-
78-
// figure out new id
79-
newID := RandStringRunes(8)
80-
81-
// perform mutation operation here
82-
// for e.g. create a Todo and save to DB.
83-
newTodo := Todo{
84-
ID: newID,
85-
Text: text,
86-
Done: false,
87-
}
88-
89-
TodoList = append(TodoList, newTodo)
90-
91-
// return the new Todo object that we supposedly save to DB
92-
// Note here that
93-
// - we are returning a `Todo` struct instance here
94-
// - we previously specified the return Type to be `todoType`
95-
// - `Todo` struct maps to `todoType`, as defined in `todoType` ObjectConfig`
96-
return newTodo, nil
97-
},
98-
},
99-
/*
100-
curl -g 'http://localhost:8080/graphql?query=mutation+_{updateTodo(id:"a",done:true){id,text,done}}'
101-
*/
102-
"updateTodo": &graphql.Field{
103-
Type: todoType, // the return type for this field
104-
Description: "Update existing todo, mark it done or not done",
105-
Args: graphql.FieldConfigArgument{
106-
"done": &graphql.ArgumentConfig{
107-
Type: graphql.Boolean,
108-
},
109-
"id": &graphql.ArgumentConfig{
110-
Type: graphql.NewNonNull(graphql.String),
111-
},
112-
},
113-
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
114-
// marshall and cast the argument value
115-
done, _ := params.Args["done"].(bool)
116-
id, _ := params.Args["id"].(string)
117-
affectedTodo := Todo{}
118-
119-
// Search list for todo with id and change the done variable
120-
for i := 0; i < len(TodoList); i++ {
121-
if TodoList[i].ID == id {
122-
TodoList[i].Done = done
123-
// Assign updated todo so we can return it
124-
affectedTodo = TodoList[i]
125-
break
126-
}
127-
}
128-
// Return affected todo
129-
return affectedTodo, nil
130-
},
131-
},
132-
},
133-
})
134-
135-
// root query
136-
// we just define a trivial example here, since root query is required.
137-
// Test with curl
138-
// curl -g 'http://localhost:8080/graphql?query={lastTodo{id,text,done}}'
139-
var rootQuery = graphql.NewObject(graphql.ObjectConfig{
140-
Name: "RootQuery",
141-
Fields: graphql.Fields{
142-
143-
/*
144-
curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
145-
*/
146-
"todo": &graphql.Field{
147-
Type: todoType,
148-
Description: "Get single todo",
149-
Args: graphql.FieldConfigArgument{
150-
"id": &graphql.ArgumentConfig{
151-
Type: graphql.String,
152-
},
153-
},
154-
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
155-
156-
idQuery, isOK := params.Args["id"].(string)
157-
if isOK {
158-
// Search for el with id
159-
for _, todo := range TodoList {
160-
if todo.ID == idQuery {
161-
return todo, nil
162-
}
163-
}
164-
}
165-
166-
return Todo{}, nil
167-
},
168-
},
169-
170-
"lastTodo": &graphql.Field{
171-
Type: todoType,
172-
Description: "Last todo added",
173-
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
174-
return TodoList[len(TodoList)-1], nil
175-
},
176-
},
177-
178-
/*
179-
curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
180-
*/
181-
"todoList": &graphql.Field{
182-
Type: graphql.NewList(todoType),
183-
Description: "List of todos",
184-
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
185-
return TodoList, nil
186-
},
187-
},
188-
},
189-
})
190-
191-
// define schema, with our rootQuery and rootMutation
192-
var schema, _ = graphql.NewSchema(graphql.SchemaConfig{
193-
Query: rootQuery,
194-
Mutation: rootMutation,
195-
})
196-
19723
func executeQuery(query string, schema graphql.Schema) *graphql.Result {
19824
result := graphql.Do(graphql.Params{
19925
Schema: schema,
@@ -207,7 +33,7 @@ func executeQuery(query string, schema graphql.Schema) *graphql.Result {
20733

20834
func main() {
20935
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
210-
result := executeQuery(r.URL.Query().Get("query"), schema)
36+
result := executeQuery(r.URL.Query().Get("query"), schema.TodoSchema)
21137
json.NewEncoder(w).Encode(result)
21238
})
21339
// Serve static files

examples/todo/schema/schema.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package schema
2+
3+
import (
4+
"math/rand"
5+
6+
"github.com/graphql-go/graphql"
7+
)
8+
9+
var TodoList []Todo
10+
11+
type Todo struct {
12+
ID string `json:"id"`
13+
Text string `json:"text"`
14+
Done bool `json:"done"`
15+
}
16+
17+
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
18+
19+
func RandStringRunes(n int) string {
20+
b := make([]rune, n)
21+
for i := range b {
22+
b[i] = letterRunes[rand.Intn(len(letterRunes))]
23+
}
24+
return string(b)
25+
}
26+
27+
// define custom GraphQL ObjectType `todoType` for our Golang struct `Todo`
28+
// Note that
29+
// - the fields in our todoType maps with the json tags for the fields in our struct
30+
// - the field type matches the field type in our struct
31+
var todoType = graphql.NewObject(graphql.ObjectConfig{
32+
Name: "Todo",
33+
Fields: graphql.Fields{
34+
"id": &graphql.Field{
35+
Type: graphql.String,
36+
},
37+
"text": &graphql.Field{
38+
Type: graphql.String,
39+
},
40+
"done": &graphql.Field{
41+
Type: graphql.Boolean,
42+
},
43+
},
44+
})
45+
46+
// root mutation
47+
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
48+
Name: "RootMutation",
49+
Fields: graphql.Fields{
50+
/*
51+
curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
52+
*/
53+
"createTodo": &graphql.Field{
54+
Type: todoType, // the return type for this field
55+
Description: "Create new todo",
56+
Args: graphql.FieldConfigArgument{
57+
"text": &graphql.ArgumentConfig{
58+
Type: graphql.NewNonNull(graphql.String),
59+
},
60+
},
61+
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
62+
63+
// marshall and cast the argument value
64+
text, _ := params.Args["text"].(string)
65+
66+
// figure out new id
67+
newID := RandStringRunes(8)
68+
69+
// perform mutation operation here
70+
// for e.g. create a Todo and save to DB.
71+
newTodo := Todo{
72+
ID: newID,
73+
Text: text,
74+
Done: false,
75+
}
76+
77+
TodoList = append(TodoList, newTodo)
78+
79+
// return the new Todo object that we supposedly save to DB
80+
// Note here that
81+
// - we are returning a `Todo` struct instance here
82+
// - we previously specified the return Type to be `todoType`
83+
// - `Todo` struct maps to `todoType`, as defined in `todoType` ObjectConfig`
84+
return newTodo, nil
85+
},
86+
},
87+
/*
88+
curl -g 'http://localhost:8080/graphql?query=mutation+_{updateTodo(id:"a",done:true){id,text,done}}'
89+
*/
90+
"updateTodo": &graphql.Field{
91+
Type: todoType, // the return type for this field
92+
Description: "Update existing todo, mark it done or not done",
93+
Args: graphql.FieldConfigArgument{
94+
"done": &graphql.ArgumentConfig{
95+
Type: graphql.Boolean,
96+
},
97+
"id": &graphql.ArgumentConfig{
98+
Type: graphql.NewNonNull(graphql.String),
99+
},
100+
},
101+
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
102+
// marshall and cast the argument value
103+
done, _ := params.Args["done"].(bool)
104+
id, _ := params.Args["id"].(string)
105+
affectedTodo := Todo{}
106+
107+
// Search list for todo with id and change the done variable
108+
for i := 0; i < len(TodoList); i++ {
109+
if TodoList[i].ID == id {
110+
TodoList[i].Done = done
111+
// Assign updated todo so we can return it
112+
affectedTodo = TodoList[i]
113+
break
114+
}
115+
}
116+
// Return affected todo
117+
return affectedTodo, nil
118+
},
119+
},
120+
},
121+
})
122+
123+
// root query
124+
// we just define a trivial example here, since root query is required.
125+
// Test with curl
126+
// curl -g 'http://localhost:8080/graphql?query={lastTodo{id,text,done}}'
127+
var rootQuery = graphql.NewObject(graphql.ObjectConfig{
128+
Name: "RootQuery",
129+
Fields: graphql.Fields{
130+
131+
/*
132+
curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
133+
*/
134+
"todo": &graphql.Field{
135+
Type: todoType,
136+
Description: "Get single todo",
137+
Args: graphql.FieldConfigArgument{
138+
"id": &graphql.ArgumentConfig{
139+
Type: graphql.String,
140+
},
141+
},
142+
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
143+
144+
idQuery, isOK := params.Args["id"].(string)
145+
if isOK {
146+
// Search for el with id
147+
for _, todo := range TodoList {
148+
if todo.ID == idQuery {
149+
return todo, nil
150+
}
151+
}
152+
}
153+
154+
return Todo{}, nil
155+
},
156+
},
157+
158+
"lastTodo": &graphql.Field{
159+
Type: todoType,
160+
Description: "Last todo added",
161+
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
162+
return TodoList[len(TodoList)-1], nil
163+
},
164+
},
165+
166+
/*
167+
curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
168+
*/
169+
"todoList": &graphql.Field{
170+
Type: graphql.NewList(todoType),
171+
Description: "List of todos",
172+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
173+
return TodoList, nil
174+
},
175+
},
176+
},
177+
})
178+
179+
// define schema, with our rootQuery and rootMutation
180+
var TodoSchema, _ = graphql.NewSchema(graphql.SchemaConfig{
181+
Query: rootQuery,
182+
Mutation: rootMutation,
183+
})

0 commit comments

Comments
 (0)