Skip to content

Instantly share code, notes, and snippets.

@birowo
Last active October 26, 2018 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save birowo/01be2785bdd3b8a875ac1803be79888f to your computer and use it in GitHub Desktop.
Save birowo/01be2785bdd3b8a875ac1803be79888f to your computer and use it in GitHub Desktop.
latihan graphql dengan library: https://github.com/graph-gophers/graphql-go yang dikatakan lebih mudah dibanding library lainnya: https://medium.com/open-graphql/choosing-a-graphql-server-library-in-go-8836f893881b

jadi di graphql ada schema & resolver

di schema ada normal query untuk mendapatkan data & mutation query untuk memanipulasi data

setiap field pada type structure di kode implementasinya harus dibuatkan method resolver-nya

jika field ada parameters-nya maka parameters di method resolver-nya jadi berada dalam args struct

tanda ! di Type dalam schema artinya not null / required & di implementasinya jadi tanpa pakai pointer / reference

atau dengan kata lain jika Type dalam schema tanpa ! artinya optional maka di implementasinya jadi harus pakai pointer / reference

hubungan antara ! di Type dalam schema dengan pointer/reference di Type dalama implementasi ini yang harus secara teliti diperhatikan & ini yang pada awalnya sempat membuat susah dipahami sampai saya membaca graph-gophers/graphql-go#240 (comment)

nah! karena saya baru mulai belajar graphql mungkin masih ada yang salah / kurang tepat dan masih banyak yang harus dipelajari

package main
import (
"encoding/json"
"net/http"
"sync"
"github.com/graph-gophers/graphql-go"
)
type tmap struct {
lock,
unlock func()
kv map[string]*string
}
func newMap() *tmap {
mu := &sync.Mutex{}
return &tmap{mu.Lock, mu.Unlock, map[string]*string{}}
}
func (kv *tmap) set(k, v string) {
kv.kv[k] = &v
}
func (kv *tmap) get(k string) (*string, bool) {
v, ok := kv.kv[k]
return v, ok
}
type keysVals struct {
ks []string
vs []*string
}
func (kv *tmap) getAll() *keysVals {
vMap := kv.kv
ks := make([]string, len(vMap))
vs := make([]*string, len(vMap))
i := 0
for k, v := range vMap {
ks[i] = k
vs[i] = v
i++
}
return &keysVals{ks, vs}
}
func (kv *tmap) del(k string) {
delete(kv.kv, k)
}
type (
Resolver struct{}
)
var kv = newMap()
func (_ *Resolver) Ins(args struct {
K string
V string
}) bool {
kv.lock()
_, ok := kv.get(args.K)
allowSet := !ok
if allowSet {
kv.set(args.K, args.V)
}
kv.unlock()
return allowSet
}
func (_ *Resolver) BulkIns(args struct {
Ks []string
Vs []string
}) int32 {
ks, vs := args.Ks, args.Vs
l := len(ks)
if len(vs) < l {
l = len(vs)
}
i := int32(0)
kv.lock()
for j, k := range ks[:l] {
_, ok := kv.get(k)
if !ok {
kv.set(k, vs[j])
i++
}
}
kv.unlock()
return i
}
func (_ *Resolver) Get(args struct{ K string }) *string {
ret, _ := kv.get(args.K)
return ret
}
func (this *keysVals) Ks() []string {
return this.ks
}
func (this *keysVals) Vs() []*string {
return this.vs
}
func (_ *Resolver) GetAll() *keysVals {
kv.lock()
ret := kv.getAll()
kv.unlock()
return ret
}
func (_ *Resolver) Update(args struct{ K, V string }) bool {
kv.lock()
_, ok := kv.get(args.K)
if ok {
kv.set(args.K, args.V)
}
kv.unlock()
return ok
}
func (_ *Resolver) Del(args struct{ K string }) bool {
kv.lock()
_, ok := kv.get(args.K)
if ok {
kv.del(args.K)
}
kv.unlock()
return ok
}
var s = `
schema {
query: Query
mutation: Mutation
}
type KeysVals {
ks: [String!]!
vs: [String]!
}
type Query {
get(k: String!): String
getAll(): KeysVals
}
type Mutation {
ins(k: String!, v: String!): Boolean!
bulkIns(ks: [String!]!, vs:[String!]!): Int!
update(k: String!, v: String!): Boolean!
del(k: String!): Boolean!
}
`
func main() {
schema := graphql.MustParseSchema(s, &Resolver{})
http.ListenAndServe(":8080", http.HandlerFunc(func(hrw http.ResponseWriter, hr *http.Request) {
switch hr.Method {
case "GET":
query := hr.URL.Query()
if len(query) == 0 {
hrw.Header().Set("Content-Type", "text/html")
hrw.Write([]byte(`
<form method="POST" target="response">
mutation:<br>
<textarea name="mutation"></textarea><br>
<input type="submit" value="submit">
</form>
<form target="response">
query:<br>
<textarea name="query"></textarea><br>
<input type="submit" value="submit">
</form>
<div style="width:300px; height:100px; overflow:auto; resize:both">
response:<br>
<iframe name="response" style="width:100%; height:100%"></iframe>
</div>
`))
return
}
for k, v := range query {
switch k {
case "query":
hrw.Header().Set("Content-Type", "application/json")
json.NewEncoder(hrw).Encode(schema.Exec(hr.Context(), v[0], "", nil))
default:
http.Error(hrw, "resource not found", http.StatusNotFound)
}
return
}
case "POST":
hr.ParseForm()
for k, v := range hr.PostForm {
switch k {
case "mutation":
hrw.Header().Set("Content-Type", "application/json")
json.NewEncoder(hrw).Encode(schema.Exec(hr.Context(), v[0], "", nil))
default:
http.Error(hrw, "resource not found", http.StatusNotFound)
}
return
}
default:
http.Error(hrw, "method not allowed", http.StatusMethodNotAllowed)
}
}))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment