Skip to content

Commit bded7d4

Browse files
author
Salman Ahmad
committed
Added example and fixed bug
1 parent 7c3c153 commit bded7d4

File tree

4 files changed

+251
-1
lines changed

4 files changed

+251
-1
lines changed

example/social/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Social App
2+
3+
A simple example of how to use struct fields as resolvers instead of methods.
4+
5+
To run this server
6+
7+
`go ./example/field-resolvers/server/server.go`
8+
9+
and go to localhost:9011 to interact

example/social/server/server.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
7+
"github.com/graph-gophers/graphql-go"
8+
"github.com/graph-gophers/graphql-go/config"
9+
"github.com/graph-gophers/graphql-go/example/social"
10+
"github.com/graph-gophers/graphql-go/relay"
11+
)
12+
13+
var schema *graphql.Schema
14+
15+
func init() {
16+
schema = graphql.MustParseSchema(social.Schema, &social.Resolver{}, &config.Config{UseResolverMethods: false})
17+
}
18+
19+
func main() {
20+
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
21+
w.Write(page)
22+
}))
23+
24+
http.Handle("/query", &relay.Handler{Schema: schema})
25+
26+
log.Fatal(http.ListenAndServe(":9011", nil))
27+
}
28+
29+
var page = []byte(`
30+
<!DOCTYPE html>
31+
<html>
32+
<head>
33+
<link href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.11/graphiql.min.css" rel="stylesheet" />
34+
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
35+
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
36+
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
37+
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
38+
<script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.11/graphiql.min.js"></script>
39+
</head>
40+
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden;">
41+
<div id="graphiql" style="height: 100vh;">Loading...</div>
42+
<script>
43+
function graphQLFetcher(graphQLParams) {
44+
return fetch("/query", {
45+
method: "post",
46+
body: JSON.stringify(graphQLParams),
47+
credentials: "include",
48+
}).then(function (response) {
49+
return response.text();
50+
}).then(function (responseBody) {
51+
try {
52+
return JSON.parse(responseBody);
53+
} catch (error) {
54+
return responseBody;
55+
}
56+
});
57+
}
58+
59+
ReactDOM.render(
60+
React.createElement(GraphiQL, {fetcher: graphQLFetcher}),
61+
document.getElementById("graphiql")
62+
);
63+
</script>
64+
</body>
65+
</html>
66+
`)

example/social/social.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package social
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
)
8+
9+
const Schema = `
10+
schema {
11+
query: Query
12+
}
13+
14+
type Query {
15+
admin(id: ID!, role: Role = ADMIN): Admin!
16+
user(id: ID!): User!
17+
}
18+
19+
interface Admin {
20+
id: ID!
21+
name: String!
22+
role: Role!
23+
}
24+
25+
type User implements Admin {
26+
id: ID!
27+
name: String!
28+
email: String!
29+
role: Role!
30+
phone: String!
31+
address: [String!]
32+
friends(page: Pagination): [User]
33+
}
34+
35+
input Pagination {
36+
first: Int
37+
last: Int
38+
}
39+
40+
enum Role {
41+
ADMIN
42+
USER
43+
}
44+
`
45+
46+
type page struct {
47+
First *int
48+
Last *int
49+
}
50+
51+
type admin interface {
52+
IdResolver() string
53+
NameResolver() string
54+
RoleResolver() string
55+
}
56+
57+
type user struct {
58+
Id string
59+
Name string
60+
Role string
61+
Email string
62+
Phone string
63+
Address *[]string
64+
Friends *[]*user
65+
}
66+
67+
func (u user) IdResolver() string {
68+
return u.Id
69+
}
70+
71+
func (u user) NameResolver() string {
72+
return u.Name
73+
}
74+
75+
func (u user) RoleResolver() string {
76+
return u.Role
77+
}
78+
79+
func (u user) FriendsResolver(args struct{ Page *page }) (*[]*user, error) {
80+
81+
from := 0
82+
numFriends := len(*u.Friends)
83+
to := numFriends
84+
85+
if args.Page != nil {
86+
if args.Page.First != nil {
87+
from = *args.Page.First
88+
}
89+
if args.Page.Last != nil {
90+
to = *args.Page.Last
91+
if to > numFriends {
92+
to = numFriends
93+
}
94+
}
95+
}
96+
97+
friends := (*u.Friends)[from:to]
98+
99+
return &friends, nil
100+
}
101+
102+
var users = []*user{
103+
{
104+
Id: "0x01",
105+
Name: "Albus Dumbledore",
106+
Role: "ADMIN",
107+
108+
Phone: "000-000-0000",
109+
Address: &[]string{"Office @ Hogwarts", "where Horcruxes are"},
110+
},
111+
{
112+
Id: "0x02",
113+
Name: "Harry Potter",
114+
Role: "USER",
115+
116+
Phone: "000-000-0001",
117+
Address: &[]string{"123 dorm room @ Hogwarts", "456 random place"},
118+
},
119+
{
120+
Id: "0x03",
121+
Name: "Hermione Granger",
122+
Role: "USER",
123+
124+
Phone: "000-000-0011",
125+
Address: &[]string{"233 dorm room @ Hogwarts", "786 @ random place"},
126+
},
127+
{
128+
Id: "0x04",
129+
Name: "Ronald Weasley",
130+
Role: "USER",
131+
132+
Phone: "000-000-0111",
133+
Address: &[]string{"411 dorm room @ Hogwarts", "981 @ random place"},
134+
},
135+
}
136+
137+
var usersMap = make(map[string]*user)
138+
139+
func init() {
140+
users[0].Friends = &[]*user{users[1]}
141+
users[1].Friends = &[]*user{users[0], users[2], users[3]}
142+
users[2].Friends = &[]*user{users[1], users[3]}
143+
users[3].Friends = &[]*user{users[1], users[2]}
144+
for _, usr := range users {
145+
usersMap[usr.Id] = usr
146+
}
147+
}
148+
149+
type Resolver struct{}
150+
151+
func (r *Resolver) Admin(ctx context.Context, args struct {
152+
Id string
153+
Role string
154+
}) (admin, error) {
155+
if usr, ok := usersMap[args.Id]; ok {
156+
if usr.Role == args.Role {
157+
return *usr, nil
158+
}
159+
}
160+
err := fmt.Sprintf("user with id=%s and role=%s does not exist", args.Id, args.Role)
161+
return user{}, errors.New(err)
162+
}
163+
164+
func (r *Resolver) User(ctx context.Context, args struct{ Id string }) (user, error) {
165+
if usr, ok := usersMap[args.Id]; ok {
166+
return *usr, nil
167+
}
168+
err := fmt.Sprintf("user with id=%s does not exist", args.Id)
169+
return user{}, errors.New(err)
170+
}

internal/exec/exec.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,12 @@ func execFieldSelection(ctx context.Context, r *Request, f *fieldToExec, path *p
192192
return err
193193
}
194194
} else {
195-
result = f.resolver.Field(f.field.FieldIndex)
195+
// TODO extract out unwrapping ptr logic to a common place
196+
res := f.resolver
197+
if res.Kind() == reflect.Ptr {
198+
res = res.Elem()
199+
}
200+
result = res.Field(f.field.FieldIndex)
196201
}
197202

198203
return nil

0 commit comments

Comments
 (0)