-
Notifications
You must be signed in to change notification settings - Fork 18
/
blogPart1.txt
168 lines (131 loc) · 5.46 KB
/
blogPart1.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
For this demo we have used golang gqlgen package, mysql and reactjs apollo-client.
For better understanding we have used mysql for database.
Purpose of this demo is to showcase graphql query, mutation and subscription in golang.
Although gqlgen original documantation is good but I thought its best to do CRUD saperatly for learning purpose.
I hope this will great help to someone starting golang graphql.
I am considering reader has little knowledge of golang and database connection in golang
This is part1 of two searies tutorial
1. golang gqlgen backend
2. reactjs apollo-client front end which using this golang backend.
what is gqlgen?
Its golang package cum utility which allows us to auto generate golang code stub from graphql schema automatically.
Their original getting started is good to read but I will mention steps here also.
Step 1 :
> Install gqlgen
$ go get -u github.com/99designs/gqlgen github.com/vektah/gorunpkg
> All the code we will be doing should reside in go/src folder.
So purpose of this demo
~/go/src/golang-gqlgen-reactjs-subscription-demo/golang
this is preferred path.
Step 2:
so first we need to create our required graphql schema.
Create schema.graphql file with below:
type Channel {
id: Int! # "!" denotes a required field
name: String!
}
type Query {
channels: [Channel!]!
}
type Mutation {
addChannel(name: String!): Channel!
updateChannel(id:Int!,name: String!): Channel!
deleteChannel(ID: Int!): Channel!
}
type Subscription {
subscriptionChannelAdded: Channel!
subscriptionChannelDeleted: Channel!
subscriptionChannelUpdated: Channel!
}
then next file we need is gqlgen.yml
this file is responsible to direct gqlgen where to autogenerate files.
for our demo purpose content will be as below
schema: schema.graphql
exec:
filename: app/graph/generated.go
model:
filename: app/model/models_gen.go
resolver:
filename: app/resolver/resolver.go
type: Resolver
Step 3:
inside our mentioned folder fire command
$ gqlgen
this will generate below files if you are first time running it.
app/graph/generated.go
app/model/models_gen.go
app/resolver/resolver.go (if this file exists it will not be regenrated)
Step 4:
So first thing will require for us is graphql query to get all channels.
As we have followed little different structure for ease of understanding and maintanance.
Create file app/resolver/ChannelResolver.go
func (r *queryResolver) Channels(ctx context.Context) ([]model.Channel, error) {
db := connection.DbConn()
var query = "SELECT * FROM channel"
selDB, err := db.Query(query)
var arrChannel []model.Channel
for selDB.Next() {
var name string
var id int64
err = selDB.Scan(&id, &name)
if err != nil {
panic(err.Error())
}
todo1 := model.Channel{ID: int(id), Name: name}
arrChannel = append(arrChannel, todo1)
}
defer db.Close()
return arrChannel, nil
}
dont forget to remove below funciton from resolver.go file
Channels(ctx context.Context) ([]model.Channel, error)
For now we will consontrate only on Add Channel Mutation and Subscription
(although we have included Edit/Delete Channels mutation and subscription)
For subscription we need to create one observer for our channel list
var addChannelObserver map[string]chan model.Channel
Now in ChannelResolver.go init we set blank model.Channel Object in addChannelObserver
func init() {
addChannelObserver = map[string]chan model.Channel{}
}
When any new channel added we need to add newly added channel into our addChannelObserver
func (r *mutationResolver) AddChannel(ctx context.Context, name string) (model.Channel, error) {
db := connection.DbConn()
insForm, err := db.Prepare("INSERT INTO channel(name) VALUES(?)")
if err != nil {
panic(err.Error())
}
var newChannel model.Channel
res, err := insForm.Exec(name)
if err != nil {
println("Exec err:", err.Error())
} else {
var id int64
id, err := res.LastInsertId()
if err != nil {
println("Error:", err.Error())
} else {
newChannel = model.Channel{ID: int(id), Name: name}
}
}
defer db.Close()
// Add new chanel in addChannelObserver
for _, observer := range addChannelObserver {
observer <- newChannel
}
return newChannel, nil
}
Now we will create function to fire subscription for channelAdded
func (r *subscriptionResolver) SubscriptionChannelAdded(ctx context.Context) (<-chan model.Channel, error) {
id := randString(8)
events := make(chan model.Channel, 1)
go func() {
<-ctx.Done()
delete(addChannelObserver, id)
}()
addChannelObserver[id] = events
return events, nil
}
We can run this code with
$ go run main.go
and url will be http://localhost:8888
That is all for golang code