Skip to content

Commit

Permalink
Merge pull request #91 from graphql-go/examples-todo
Browse files Browse the repository at this point in the history
Adds todo example.
  • Loading branch information
chris-ramon committed Dec 19, 2015
2 parents 285e047 + b300ff4 commit e692c16
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 0 deletions.
28 changes: 28 additions & 0 deletions examples/todo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Go GraphQL ToDo example

An example that consists of basic core GraphQL queries and mutations.

To run the example navigate to the example directory by using your shell of choice.

```
cd examples/todo
```

Run the example, it will spawn a GraphQL HTTP endpoint

```
go run main.go
```

Execute queries via shell.

```
// To get single ToDo item by ID
curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
// To create a ToDo item
curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
// To get a list of ToDo items
curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
```
185 changes: 185 additions & 0 deletions examples/todo/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package main

import (
"encoding/json"
"fmt"
"math/rand"
"net/http"
"time"

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

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)

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
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
},
},
},
})

// 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,
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,
RequestString: query,
})
if len(result.Errors) > 0 {
fmt.Printf("wrong result, unexpected errors: %v", result.Errors)
}
return result
}

func main() {

http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
result := executeQuery(r.URL.Query()["query"][0], schema)
json.NewEncoder(w).Encode(result)
})

fmt.Println("Now server is running on port 8080")
fmt.Println("Get single todo: curl -g 'http://localhost:8080/graphql?query={todo(id:\"b\"){id,text,done}}'")
fmt.Println("Create new todo: curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:\"My+new+todo\"){id,text,done}}'")
fmt.Println("Load todo list: curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'")
http.ListenAndServe(":8080", nil)
}

0 comments on commit e692c16

Please sign in to comment.