参考graphql-go-example
设计API参数列表
type User {
id: ID
email: String!
post(id: ID!): Post
posts: [Post!]!
follower(id: ID!): User
followers: [User!]!
followee(id: ID!): User
followees: [User!]!
}
type Post {
id: ID
user: User!
title: String!
body: String!
comment(id: ID!): Comment
comments: [Comment!]!
}
type Comment {
id: ID
user: User!
post: Post!
title: String
body: String!
}
[Type]! 或者[Type!] 或者[Type!]! (请仔细看这里! 的位置),它们的含义分别为:
- 列表本身为必填项,但其内部元素可以为空
- 列表本身可以为空,但是其内部元素为必填
- 列表本身和内部元素均为必填
转换为go的实现(User为例)
var UserType = graphql.NewObject(graphql.ObjectConfig{
Name: "User",
Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.NewNonNull(graphql.ID),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
return user.ID, nil
}
return nil, nil
},
},
"email": &graphql.Field{
Type: graphql.NewNonNull(graphql.String),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
return user.Email, nil
}
return nil, nil
},
},
},
})
func init() {
UserType.AddFieldConfig("post", &graphql.Field{
Type: PostType,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Description: "Post ID",
Type: graphql.NewNonNull(graphql.ID),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
i := p.Args["id"].(string)
id, err := strconv.Atoi(i)
if err != nil {
return nil, err
}
return GetPostByIDAndUser(id, user.ID)
}
return nil, nil
},
})
UserType.AddFieldConfig("posts", &graphql.Field{
Type: graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(PostType))),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
return GetPostsForUser(user.ID)
}
return []Post{}, nil
},
})
UserType.AddFieldConfig("follower", &graphql.Field{
Type: UserType,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Description: "Follower ID",
Type: graphql.NewNonNull(graphql.ID),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
i := p.Args["id"].(string)
id, err := strconv.Atoi(i)
if err != nil {
return nil, err
}
return GetFollowerByIDAndUser(id, user.ID)
}
return nil, nil
},
})
UserType.AddFieldConfig("followers", &graphql.Field{
Type: graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(UserType))),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
return GetFollowersForUser(user.ID)
}
return []User{}, nil
},
})
UserType.AddFieldConfig("followee", &graphql.Field{
Type: UserType,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Description: "Followee ID",
Type: graphql.NewNonNull(graphql.ID),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
i := p.Args["id"].(string)
id, err := strconv.Atoi(i)
if err != nil {
return nil, err
}
return GetFolloweeByIDAndUser(id, user.ID)
}
return nil, nil
},
})
UserType.AddFieldConfig("followees", &graphql.Field{
Type: graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(UserType))),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if user, ok := p.Source.(*User); ok == true {
return GetFolloweesForUser(user.ID)
}
return []User{}, nil
},
})
}
API查询
graphql设计模式有三种查询类型
- query(查询):当获取数据时,应当选取Query类型
- mutation(更改):当尝试修改数据时,应当使用mutation类型
- subscription(订阅):当希望数据更改时,可以进行消息推送,使用subscription类型
query和mutation设计如下:
type Query {
user(id: ID!): User
}
type Mutation {
createUser(email: String!): User
removeUser(id: ID!): Boolean
follow(follower: ID!, followee: ID!): Boolean
unfollow(follower: ID!, followee: ID!): Boolean
createPost(user: ID!, title: String!, body: String!): Post
removePost(id: ID!): Boolean
createComment(user: ID!, post: ID!, title: String!, body: String!): Comment
removeComment(id: ID!): Boolean
}
转换为go的实现
var QueryType = graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"user": &graphql.Field{
Type: UserType,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Description: "User ID",
Type: graphql.NewNonNull(graphql.ID),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
i := p.Args["id"].(string)
id, err := strconv.Atoi(i)
if err != nil {
return nil, err
}
return GetUserByID(id)
},
},
},
})
var MutationType = graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"createUser": &graphql.Field{
Type: UserType,
Args: graphql.FieldConfigArgument{
"email": &graphql.ArgumentConfig{
Description: "New User Email",
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
email := p.Args["email"].(string)
user := &User{
Email: email,
}
err := InsertUser(user)
return user, err
},
},
"removeUser": &graphql.Field{
Type: graphql.Boolean,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Description: "User ID to remove",
Type: graphql.NewNonNull(graphql.ID),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
i := p.Args["id"].(string)
id, err := strconv.Atoi(i)
if err != nil {
return nil, err
}
err = RemoveUserByID(id)
return (err == nil), err
},
},
},
})
接口的启用也很简单
func main() {
schema, err := graphql.NewSchema(graphql.SchemaConfig{
Query: QueryType,
Mutation: MutationType,
})
if err != nil {
log.Fatal(err)
}
http.Handle("/graphql", handler(schema))
log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil))
}
func handler(schema graphql.Schema) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
query, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
result := graphql.Do(graphql.Params{
Schema: schema,
RequestString: string(query),
})
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(result)
}
}
请求实例
|
请发表评论