Skip to content

Commit

Permalink
Merge pull request #574 from graphql-go/examples-todo-schema
Browse files Browse the repository at this point in the history
examples/todo: extracts TodoSchema
  • Loading branch information
chris-ramon committed Oct 11, 2020
2 parents d6b7434 + 279aceb commit 05c348c
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 180 deletions.
186 changes: 6 additions & 180 deletions examples/todo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,192 +8,18 @@ import (
"time"

"github.com/graphql-go/graphql"
"github.com/graphql-go/graphql/examples/todo/schema"
)

type Todo struct {
ID string `json:"id"`
Text string `json:"text"`
Done bool `json:"done"`
}

var TodoList []Todo
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

func init() {
todo1 := Todo{ID: "a", Text: "A todo not to forget", Done: false}
todo2 := Todo{ID: "b", Text: "This is the most important", Done: false}
todo3 := Todo{ID: "c", Text: "Please do this or else", Done: false}
TodoList = append(TodoList, todo1, todo2, todo3)
todo1 := schema.Todo{ID: "a", Text: "A todo not to forget", Done: false}
todo2 := schema.Todo{ID: "b", Text: "This is the most important", Done: false}
todo3 := schema.Todo{ID: "c", Text: "Please do this or else", Done: false}
schema.TodoList = append(schema.TodoList, todo1, todo2, todo3)

rand.Seed(time.Now().UnixNano())
}

// define custom GraphQL ObjectType `todoType` for our Golang struct `Todo`
// Note that
// - the fields in our todoType maps with the json tags for the fields in our struct
// - the field type matches the field type in our struct
var todoType = graphql.NewObject(graphql.ObjectConfig{
Name: "Todo",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.String,
},
"text": &graphql.Field{
Type: graphql.String,
},
"done": &graphql.Field{
Type: graphql.Boolean,
},
},
})

// root mutation
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
Name: "RootMutation",
Fields: graphql.Fields{
/*
curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
*/
"createTodo": &graphql.Field{
Type: todoType, // the return type for this field
Description: "Create new todo",
Args: graphql.FieldConfigArgument{
"text": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {

// marshall and cast the argument value
text, _ := params.Args["text"].(string)

// figure out new id
newID := RandStringRunes(8)

// perform mutation operation here
// for e.g. create a Todo and save to DB.
newTodo := Todo{
ID: newID,
Text: text,
Done: false,
}

TodoList = append(TodoList, newTodo)

// return the new Todo object that we supposedly save to DB
// Note here that
// - we are returning a `Todo` struct instance here
// - we previously specified the return Type to be `todoType`
// - `Todo` struct maps to `todoType`, as defined in `todoType` ObjectConfig`
return newTodo, nil
},
},
/*
curl -g 'http://localhost:8080/graphql?query=mutation+_{updateTodo(id:"a",done:true){id,text,done}}'
*/
"updateTodo": &graphql.Field{
Type: todoType, // the return type for this field
Description: "Update existing todo, mark it done or not done",
Args: graphql.FieldConfigArgument{
"done": &graphql.ArgumentConfig{
Type: graphql.Boolean,
},
"id": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
// marshall and cast the argument value
done, _ := params.Args["done"].(bool)
id, _ := params.Args["id"].(string)
affectedTodo := Todo{}

// Search list for todo with id and change the done variable
for i := 0; i < len(TodoList); i++ {
if TodoList[i].ID == id {
TodoList[i].Done = done
// Assign updated todo so we can return it
affectedTodo = TodoList[i]
break
}
}
// Return affected todo
return affectedTodo, nil
},
},
},
})

// root query
// we just define a trivial example here, since root query is required.
// Test with curl
// curl -g 'http://localhost:8080/graphql?query={lastTodo{id,text,done}}'
var rootQuery = graphql.NewObject(graphql.ObjectConfig{
Name: "RootQuery",
Fields: graphql.Fields{

/*
curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
*/
"todo": &graphql.Field{
Type: todoType,
Description: "Get single todo",
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {

idQuery, isOK := params.Args["id"].(string)
if isOK {
// Search for el with id
for _, todo := range TodoList {
if todo.ID == idQuery {
return todo, nil
}
}
}

return Todo{}, nil
},
},

"lastTodo": &graphql.Field{
Type: todoType,
Description: "Last todo added",
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
return TodoList[len(TodoList)-1], nil
},
},

/*
curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
*/
"todoList": &graphql.Field{
Type: graphql.NewList(todoType),
Description: "List of todos",
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return TodoList, nil
},
},
},
})

// define schema, with our rootQuery and rootMutation
var schema, _ = graphql.NewSchema(graphql.SchemaConfig{
Query: rootQuery,
Mutation: rootMutation,
})

func executeQuery(query string, schema graphql.Schema) *graphql.Result {
result := graphql.Do(graphql.Params{
Schema: schema,
Expand All @@ -207,7 +33,7 @@ func executeQuery(query string, schema graphql.Schema) *graphql.Result {

func main() {
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
result := executeQuery(r.URL.Query().Get("query"), schema)
result := executeQuery(r.URL.Query().Get("query"), schema.TodoSchema)
json.NewEncoder(w).Encode(result)
})
// Serve static files
Expand Down
183 changes: 183 additions & 0 deletions examples/todo/schema/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package schema

import (
"math/rand"

"github.com/graphql-go/graphql"
)

var TodoList []Todo

type Todo struct {
ID string `json:"id"`
Text string `json:"text"`
Done bool `json:"done"`
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

// define custom GraphQL ObjectType `todoType` for our Golang struct `Todo`
// Note that
// - the fields in our todoType maps with the json tags for the fields in our struct
// - the field type matches the field type in our struct
var todoType = graphql.NewObject(graphql.ObjectConfig{
Name: "Todo",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.String,
},
"text": &graphql.Field{
Type: graphql.String,
},
"done": &graphql.Field{
Type: graphql.Boolean,
},
},
})

// root mutation
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
Name: "RootMutation",
Fields: graphql.Fields{
/*
curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
*/
"createTodo": &graphql.Field{
Type: todoType, // the return type for this field
Description: "Create new todo",
Args: graphql.FieldConfigArgument{
"text": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {

// marshall and cast the argument value
text, _ := params.Args["text"].(string)

// figure out new id
newID := RandStringRunes(8)

// perform mutation operation here
// for e.g. create a Todo and save to DB.
newTodo := Todo{
ID: newID,
Text: text,
Done: false,
}

TodoList = append(TodoList, newTodo)

// return the new Todo object that we supposedly save to DB
// Note here that
// - we are returning a `Todo` struct instance here
// - we previously specified the return Type to be `todoType`
// - `Todo` struct maps to `todoType`, as defined in `todoType` ObjectConfig`
return newTodo, nil
},
},
/*
curl -g 'http://localhost:8080/graphql?query=mutation+_{updateTodo(id:"a",done:true){id,text,done}}'
*/
"updateTodo": &graphql.Field{
Type: todoType, // the return type for this field
Description: "Update existing todo, mark it done or not done",
Args: graphql.FieldConfigArgument{
"done": &graphql.ArgumentConfig{
Type: graphql.Boolean,
},
"id": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
// marshall and cast the argument value
done, _ := params.Args["done"].(bool)
id, _ := params.Args["id"].(string)
affectedTodo := Todo{}

// Search list for todo with id and change the done variable
for i := 0; i < len(TodoList); i++ {
if TodoList[i].ID == id {
TodoList[i].Done = done
// Assign updated todo so we can return it
affectedTodo = TodoList[i]
break
}
}
// Return affected todo
return affectedTodo, nil
},
},
},
})

// root query
// we just define a trivial example here, since root query is required.
// Test with curl
// curl -g 'http://localhost:8080/graphql?query={lastTodo{id,text,done}}'
var rootQuery = graphql.NewObject(graphql.ObjectConfig{
Name: "RootQuery",
Fields: graphql.Fields{

/*
curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
*/
"todo": &graphql.Field{
Type: todoType,
Description: "Get single todo",
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {

idQuery, isOK := params.Args["id"].(string)
if isOK {
// Search for el with id
for _, todo := range TodoList {
if todo.ID == idQuery {
return todo, nil
}
}
}

return Todo{}, nil
},
},

"lastTodo": &graphql.Field{
Type: todoType,
Description: "Last todo added",
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
return TodoList[len(TodoList)-1], nil
},
},

/*
curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
*/
"todoList": &graphql.Field{
Type: graphql.NewList(todoType),
Description: "List of todos",
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return TodoList, nil
},
},
},
})

// define schema, with our rootQuery and rootMutation
var TodoSchema, _ = graphql.NewSchema(graphql.SchemaConfig{
Query: rootQuery,
Mutation: rootMutation,
})

0 comments on commit 05c348c

Please sign in to comment.