REST API返回特定结构的数据,客户端只能从返回的数据中获取自己想要的数据。
使用GraphQL API,客户端可以声明自己需要的数据,服务器将这些数据返回给客户端。
graphql-go
Schema使用SDL编写,它是一份清单,定义客户端可以进行的操作 。
schema有三个字段:query、mutation、subscription。这三个字段分别代表查询、修改和订阅。对比REST,query相当于GET请求,mutation相当于POST和DELETE请求。
例如
var s = `
schema {
query: Query
}
type Query {
hello: String!
}
`
客户端可以进行query操作,type定义查询的字段和返回的值,上面查询“hello”会返回一个String类型的值,感叹号表示查询结果非空。
type query struct{}
func (_ *query) Hello() string {
return "hello world"
}
query结构体就是query的解析器,Helllo是解析器函数。
接下来把解析器和schema绑定。
var schema = graphql.MustParseSchema(s, &query{})
使用go的http服务,将schema转换成handler,解析请求体中的json串来获得客户端的查询请求。
func main() {
h := relay.Handler{schema}
http.Handle("/hello", &h)
http.ListenAndServe(":8080", nil)
}
运行服务端,使用curl进行测试。
curl -X POST -d '{"query":"{hello}"}' localhost:8080/hello
返回结果
{"data":{"hello":"hello world"}}
数据的结构体中增加一个String数组
Friends []string
schema中定义为
friends: [String!]!
增加friends字段解析器
func (r *objectResolver) Friends() []string {
return r.o.Friends
}
数据的结构体中增加一个String数组
Episode []string
schema中增加enum的定义
enum Episode {
episode1
episode2
episode3
}
type中增加一个字段
episode: [Episode!]!
增加episode字段解析器
func (r *objectResolver) Episode() []string {
return r.o.Episode
}
可以通过带参数的查询来取得特定的数据
schema的Query字段中增加查询
objectWithEpisode(episode: Episode!): [Object!]!
类似函数定义,参数是Episode类型,返回值是Object的数组
解析器
根据参数返回对应的对象
func (r *Resolver) ObjectWithEpisode(args struct{ Episode string }) []*objectResolver {
resolvers := []*objectResolver{}
for i := 0; i < len(objects); i++ {
for _, v := range objects[i].Episode {
if args.Episode == v {
resolvers = append(resolvers, &objectResolver{objects[i]})
break
}
}
}
return resolvers
}
可以用来更新数据
schema中添加字段
mutation: Mutation
type中添加
addObject(id: ID!, name: String!, friend: String!)
解析器
func (r *Resolver) AddReview(args struct {
ID graphql.ID
Friend string
}) *objectResolver {
new_friend := args.Friend
for i := 0; i < len(objects); i++ {
if objects[i].ID == args.ID {
objects[i].Friends = append(objects[i].Friends, new_friend)
return &friendResolver{&new_friend}
}
}
return nil
}
从官方的示例中copy了一段代码,用于服务端,可以在网页中进行交互。
func main() {
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(page)
}))
h := relay.Handler{schema}
http.Handle("/object", &h)
log.Fatal(http.ListenAndServe(":8080", nil))
}
var page = []byte(`
Loading...
`)