Skip to content

Commit dde6293

Browse files
committed
Simplest step-by-step examples
1 parent aacf782 commit dde6293

File tree

8 files changed

+524
-0
lines changed

8 files changed

+524
-0
lines changed

step-by-step/README.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Simple step-by-step examples
2+
3+
Accompanying materials for my talk on [DevFest Siberia 2018](https://gdg-siberia.com/).
4+
5+
## minimal.go
6+
7+
- Minimal example: one key and on constant response as string "b"
8+
9+
```
10+
query {a}
11+
```
12+
13+
## args.go
14+
15+
- Use integer response
16+
- Two keys
17+
- Use one integer argument
18+
- List in response
19+
20+
```
21+
query {a} # Error: we need nonnull argument
22+
query {a(x:2)}
23+
query {a(x:2) b(x:5)}
24+
query {a b} # Collect all errors
25+
query {a(x:2) b(x:30)} # Error but collert all reachable data
26+
```
27+
28+
## type.go
29+
30+
- Simplest custom type with Resolver interface
31+
- Go structures not must to corelate with GraphQL structs
32+
- Resolver resolves each field individualy
33+
- You init part of object in parent resolver
34+
35+
```
36+
query {a} # You can't call all attrs
37+
query {a {nm}}
38+
query {a {nnm}} # Try to suggest fied names
39+
```
40+
41+
## recursion.go
42+
43+
- Add field by `AddFieldConfig`
44+
45+
```
46+
query {a {nm sub{nm}}}
47+
query {a {nm sub{nm sub{nm sub{nm sub{nm}}}}}}
48+
```
49+
50+
## defer.go
51+
52+
- return `func() (interface{}, error)`
53+
- use async resolver
54+
55+
```
56+
query {a {nm}}
57+
```
58+
59+
## processing.go
60+
61+
- Order of processing
62+
63+
```
64+
query {a{seq sub{seq sub{seq sub{seq}}}}}
65+
```

step-by-step/README.run.sh

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
3+
while IFS='' read -r line || [[ -n "$line" ]]; do
4+
if [[ "$line" =~ '##' ]]
5+
then
6+
cmd="$(echo $line | sed 's/^##[[:space:]]*//')"
7+
echo "[$cmd] Run..."
8+
xterm -T "$cmd" -e go run "$cmd" &
9+
while :
10+
do
11+
started="$(netstat -lnt | grep 8080 | wc -l)"
12+
if [[ "$started" = '0' ]]
13+
then
14+
sleep 1
15+
else
16+
break
17+
fi
18+
done
19+
echo "[$cmd] Call..."
20+
while IFS='' read -r line || [[ -n "$line" ]]; do
21+
if [[ "$line" = '```' ]]
22+
then
23+
break
24+
fi
25+
done
26+
while IFS='' read -r line || [[ -n "$line" ]]; do
27+
if [[ "$line" = '```' ]]
28+
then
29+
break
30+
fi
31+
line="$(echo "$line" | sed 's-#.*--')"
32+
echo ">> $line"
33+
curl -XPOST http://localhost:8080/gql -H 'Content-Type: application/graphql' -d "$line"
34+
echo
35+
done
36+
echo "[$cmd] Kill..."
37+
kill $(jobs -p)
38+
echo "[$cmd] Wait..."
39+
wait
40+
fi
41+
done < README.md

step-by-step/args.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/graphql-go/graphql"
9+
"github.com/graphql-go/handler"
10+
)
11+
12+
func main() {
13+
queryType := graphql.NewObject(graphql.ObjectConfig{
14+
Name: "Query",
15+
Fields: graphql.Fields{
16+
"a": &graphql.Field{
17+
Name: "a",
18+
Type: graphql.Int,
19+
Args: graphql.FieldConfigArgument{
20+
"x": &graphql.ArgumentConfig{
21+
Type: graphql.NewNonNull(graphql.Int),
22+
},
23+
},
24+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
25+
x := p.Args["x"].(int)
26+
return x * x, nil
27+
},
28+
},
29+
"b": &graphql.Field{
30+
Name: "b",
31+
Type: graphql.NewList(graphql.Int),
32+
Args: graphql.FieldConfigArgument{
33+
"x": &graphql.ArgumentConfig{
34+
Type: graphql.NewNonNull(graphql.Int),
35+
},
36+
},
37+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
38+
x := p.Args["x"].(int)
39+
if x < 0 || x > 20 {
40+
return nil, errors.New("Invald arg")
41+
}
42+
r := make([]int, x)
43+
for i := 0; i < x; i++ {
44+
if i < 2 {
45+
r[i] = 1
46+
} else {
47+
r[i] = r[i-1] + r[i-2]
48+
}
49+
}
50+
return r, nil
51+
},
52+
},
53+
},
54+
})
55+
56+
var schema, err = graphql.NewSchema(graphql.SchemaConfig{
57+
Query: queryType,
58+
})
59+
if err != nil {
60+
panic(err)
61+
}
62+
63+
handler := handler.New(&handler.Config{
64+
Schema: &schema,
65+
Pretty: true,
66+
GraphiQL: true,
67+
Playground: true,
68+
})
69+
http.Handle("/gql", handler)
70+
fmt.Println("Run...")
71+
http.ListenAndServe(":8080", nil)
72+
}

step-by-step/defer.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/graphql-go/graphql"
9+
"github.com/graphql-go/handler"
10+
)
11+
12+
type Node struct {
13+
Name string
14+
}
15+
16+
func (n Node) Resolve(p graphql.ResolveParams) (interface{}, error) {
17+
switch p.Info.FieldName {
18+
case "nm":
19+
ch := make(chan string)
20+
go func() {
21+
ch <- n.Name
22+
}()
23+
return func() (interface{}, error) {
24+
result := <-ch
25+
return result, nil
26+
}, nil
27+
}
28+
return nil, errors.New("Node resolver: Unknown field " + p.Info.FieldName)
29+
}
30+
31+
func main() {
32+
33+
var nodeType = graphql.NewObject(graphql.ObjectConfig{
34+
Name: "Node",
35+
Fields: graphql.Fields{
36+
"nm": &graphql.Field{Type: graphql.NewNonNull(graphql.String)},
37+
},
38+
})
39+
40+
queryType := graphql.NewObject(graphql.ObjectConfig{
41+
Name: "Query",
42+
Fields: graphql.Fields{
43+
"a": &graphql.Field{
44+
Name: "a",
45+
Type: nodeType,
46+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
47+
return Node{"Some constant title"}, nil
48+
},
49+
},
50+
},
51+
})
52+
53+
var schema, err = graphql.NewSchema(graphql.SchemaConfig{
54+
Query: queryType,
55+
})
56+
if err != nil {
57+
panic(err)
58+
}
59+
60+
handler := handler.New(&handler.Config{
61+
Schema: &schema,
62+
Pretty: true,
63+
GraphiQL: true,
64+
Playground: true,
65+
})
66+
http.Handle("/gql", handler)
67+
fmt.Println("Run...")
68+
http.ListenAndServe(":8080", nil)
69+
}

step-by-step/minimal.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
"github.com/graphql-go/graphql"
8+
"github.com/graphql-go/handler"
9+
)
10+
11+
func main() {
12+
queryType := graphql.NewObject(graphql.ObjectConfig{
13+
Name: "Query",
14+
Fields: graphql.Fields{
15+
"a": &graphql.Field{
16+
Name: "a",
17+
Type: graphql.String,
18+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
19+
return "Value of field 'a'", nil
20+
},
21+
},
22+
},
23+
})
24+
25+
var schema, err = graphql.NewSchema(graphql.SchemaConfig{
26+
Query: queryType,
27+
})
28+
if err != nil {
29+
panic(err)
30+
}
31+
32+
handler := handler.New(&handler.Config{
33+
Schema: &schema,
34+
Pretty: true,
35+
GraphiQL: true,
36+
Playground: true,
37+
})
38+
http.Handle("/gql", handler)
39+
fmt.Println("Run...")
40+
http.ListenAndServe(":8080", nil)
41+
}

step-by-step/processing.go

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"math/rand"
7+
"net/http"
8+
"sync/atomic"
9+
"time"
10+
11+
"github.com/graphql-go/graphql"
12+
"github.com/graphql-go/handler"
13+
)
14+
15+
var actionSerial uint64
16+
17+
type Node struct {
18+
Name string
19+
Level int
20+
Start uint64
21+
Ready uint64
22+
Fin uint64
23+
}
24+
25+
func (n Node) Resolve(p graphql.ResolveParams) (interface{}, error) {
26+
switch p.Info.FieldName {
27+
case "nm":
28+
return n.Name, nil
29+
case "lvl":
30+
return n.Level, nil
31+
case "seq": // h - history
32+
return fmt.Sprintf(" %d %d %d ", n.Start, n.Ready, n.Fin), nil
33+
case "sub":
34+
nextLevel := n.Level + 1
35+
nodes := make([]interface{}, 2)
36+
for i := 0; i < 2; i++ {
37+
atomic.AddUint64(&actionSerial, 1)
38+
nn := Node{"Subnode", nextLevel, actionSerial, 0, 0}
39+
ch := make(chan Node)
40+
go func() {
41+
r := rand.Intn(90) + 10
42+
time.Sleep(time.Duration(r) * time.Millisecond)
43+
atomic.AddUint64(&actionSerial, 1)
44+
nn.Ready = actionSerial
45+
ch <- nn
46+
}()
47+
nodes[i] = func() (interface{}, error) {
48+
n := <-ch
49+
atomic.AddUint64(&actionSerial, 1)
50+
n.Fin = actionSerial
51+
return n, nil
52+
}
53+
}
54+
return nodes, nil
55+
}
56+
return nil, errors.New("Node resolver: Unknown field " + p.Info.FieldName)
57+
}
58+
59+
func main() {
60+
61+
rand.Seed(time.Now().UTC().UnixNano())
62+
63+
var nodeType = graphql.NewObject(graphql.ObjectConfig{
64+
Name: "Node",
65+
Fields: graphql.Fields{
66+
"nm": &graphql.Field{Type: graphql.NewNonNull(graphql.String)},
67+
"lvl": &graphql.Field{Type: graphql.NewNonNull(graphql.Int)},
68+
"seq": &graphql.Field{Type: graphql.NewNonNull(graphql.String)},
69+
},
70+
})
71+
72+
nodeType.AddFieldConfig("sub", &graphql.Field{
73+
Type: graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(nodeType))),
74+
})
75+
76+
queryType := graphql.NewObject(graphql.ObjectConfig{
77+
Name: "Query",
78+
Fields: graphql.Fields{
79+
"a": &graphql.Field{
80+
Name: "a",
81+
Type: nodeType,
82+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
83+
actionSerial = 0
84+
return Node{"Root node", 0, 0, 0, 0}, nil
85+
},
86+
},
87+
},
88+
})
89+
90+
var schema, err = graphql.NewSchema(graphql.SchemaConfig{
91+
Query: queryType,
92+
})
93+
if err != nil {
94+
panic(err)
95+
}
96+
97+
handler := handler.New(&handler.Config{
98+
Schema: &schema,
99+
Pretty: true,
100+
GraphiQL: true,
101+
Playground: true,
102+
})
103+
http.Handle("/gql", handler)
104+
fmt.Println("Run...")
105+
http.ListenAndServe(":8080", nil)
106+
}

0 commit comments

Comments
 (0)