在Go语言中实现GraphQL的Mutation
在这篇文章中,我将以使用Golang + MongoDB和GraphQL来尝试并且记录GraphQL的Mutation进行解释。
我将再次解释GraphQL,并将其汇总。
GraphQL 是一种查询语言和运行时环境,用于获取和修改数据。
在GraphQL中,不再像以前使用RESTful那样创建多个终点并进行通信。GraphQL只需要一个终点即可运行。
GraphQL的优点基本上是
・只需要一个终端点即可
・可以以类型安全的方式与数据库进行交互
只要牢记这两点,我认为就没有问题(如果有补充,欢迎提出)。
虽然只是简短的说明,但现在我们要谈论的是关于实施方面的事情。
尽管不是直接编写代码,我们会考虑一些概念性的东西。
GraphQL 的实现思路
首先,我希望您能以以下的感觉理解GraphQL实现的流程(我认为这个流程不仅适用于Golang,还适用于一般情况,大概)。
-
- 用GraphQL定义处理的Type(GraphQL处理数据的设置)
-
- 按照数据获取和创建的用途定义Field(在这里使用Type)
-
- 将Field组合成Schema
-
- 创建GraphQL请求(请求GraphQL查询数据库)
-
- 将Schema和请求结合起来执行GraphQL
- 返回指定的数据
我之前写过一篇关于在Golang + MongoDB中使用GraphQL的文章,但这个请求包含了两个概念,其中一个是这篇文章标题中所述的Mutation(以下简称为”变异”)。
*虽然这个术语并非官方使用的词汇,但我觉得这样的表达更容易理解。
*在流程的第4步中提到了”与数据库查询请求”,但GraphQL并不直接与数据库进行交互(根据具体实现的方式可能会直接与数据库交互)。GraphQL仅仅是在从数据库中获取到的数据集上执行操作。例如,执行一个GraphQL查询以获取特定的用户时,实际上是针对已经从数据库中获取到的用户表的所有记录(在这里,已经转换为结构体数组)进行操作。
请求包括查询和变异。
查询(类似于以前的GET)…请求获取数据
变更(类似于以前的POST)…请求更新数据
在之前的文章中,我们解释了如何使用GraphQL查询来获取数据,现在我们将介绍如何使用Mutation来插入数据。之后我们还会继续写关于更新和删除的内容。
使用Golang语言和GraphQL技术实现Mutation操作。
我们将使用NoSQL的MongoDB数据库。
上一篇文章中,GraphQL的模式定义代码如下。
rootQuery := graphql.ObjectConfig{
Name: "RootQuery",
Fields: fields.UsersField,
}
schemaConfig := graphql.SchemaConfig{
Query: graphql.NewObject(rootQuery), // Query
}
schema, err := graphql.NewSchema(schemaConfig)
if err != nil {
log.Fatalf("failed to create new schema, error: %v", err)
}
如果使用突变,则情况如下。
rootQuery := graphql.ObjectConfig{
Name: "RootQuery",
Fields: fields.UsersField,
}
rootMutation := graphql.ObjectConfig{
Name: "RootMutation",
Fields: fields.CreateUserField,
}
schemaConfig := graphql.SchemaConfig{
Query: graphql.NewObject(rootQuery), // Query
Mutation: graphql.NewObject(rootMutation), // Mutation
}
schema, err := graphql.NewSchema(schemaConfig)
if err != nil {
log.Fatalf("failed to create new schema, error: %v", err)
}
rootMutation变量被创建,并将其作为新的GraphQL对象添加到SchemaConfig的Mutation中。
*在上一篇文章中,我们在同一个文件中定义了fields,但是这次我们将其分开保存在不同的文件中,因此我们要写成fields.UsersField或fields.CreateUserField。
现在,我们来解释一下rootMutation的内容。
它并不是很复杂,可能会感觉很轻松。
rootMutation将fields.CreateUserField(在此指的是fields/user.go中的CreateUserField变量)设置为Fields。
// fields/user.go
var CreateUserField = graphql.Fields{
"createUser": &graphql.Field{
Type: types.UserType,
Description: "Create new user",
Args: graphql.FieldConfigArgument{
"name": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"email": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"password": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
name, _ := params.Args["name"].(string)
email, _ := params.Args["email"].(string)
password, _ := params.Args["password"].(string)
database.CreateNewUser(name, email, password)
return nil, nil
},
},
}
当查询获取特定用户时,原本使用“user”开头,但现在改为“createUser”。
此名称将在发送请求时使用。
只需提供一个选项:
如果您能像查询一样理解Args,那就很好了。这是您在发送请求时可以指定的元素。在代码中,它们被定义为name,email和password,这意味着您可以在发送请求时设置这些元素。对于POST请求来说,这是很常见的事情。
最后的第六行database.CreateNewUser(name, email, password)是与数据库进行交互的部分。
因为这里将代码分离,所以在外部的database目录下有一个user.go文件,用于与数据库进行交互。
database/user.go的内容如下:
// database/user.go
func CreateNewUser(name string, email string, password string) {
// connection to mongoDB
session, _ := mgo.Dial("mongodb://localhost/test")
defer session.Close()
db := session.DB("test")
// insert
newUser := &User{
Id: bson.NewObjectId(),
Name: name,
Email: email,
Password: password,
}
col := db.C("users")
if err := col.Insert(newUser); err != nil {
log.Fatalln(err)
}
}
如果你理解MongoDB的插入方法,阅读这段内容应该没有问题。
func (*Collection) Insert的意思是,这是一个指向Collection的指针的方法,用于插入操作。
好的,突变的处理到此为止。
突变过程中的动作就这些了。
使用已实现的突变(Mutation)进行利用。
要使用突变功能,必须发送执行该操作的请求。
查询请求如下所示。
request := `
{
user(id: "5c94f4d7e803694b2d09da75") {
id
name
email
password
}
}
`
如果将这个写成突变请求的形式,
request := `
mutation {
createUser(name: "name", email: "email", password: "pass") {
name
email
password
}
}
`
由于在fields/user.go文件中,createUserField被定义为名为”createUser”的字段,因此在这里使用createUser来编写变更操作。
然后,使用该参数来指定要创建的新数据的元素。
这些元素对应于createUserField的每个参数,并且它们会通过Resolve函数传递并执行Insert操作。我觉得这个问题其实挺简单的。
如果你用mongo进入数据库并查看db.users.find()之类的命令,你会发现已经添加了创建的文档。
如果没有找到的话,请尝试搜索一下笑。
嗯,我认为一旦了解了GraphQL的工作原理,基本上就能理解大部分实现方法了。
此外,实际编写并运行代码也非常重要。
如果有任何错误的表达或描述,请毫不犹豫地指出来。