
大家好! 在Habr上有很多关于GraphQL的文章,但是在浏览了它们之后,我发现它们都绕过了Go这样出色的语言。 今天,我将尝试纠正这种误解。 为此,我们将使用GraphQL在Go上编写一个API。
简而言之:GraphQL是用于构建API的查询语言,该API描述了以哪种形式请求和返回数据(有关官方资源graphql.imtqy.com和Hub的更多详细信息)
您可以认为GraphQL或REST更好。
我们将提供经典的API:CRUD(创建,读取,更新,删除)在在线商店中添加,接收,编辑和删除产品。
在服务器端,我们将使用GraphQL的现成实现graphql-go
首先,您需要下载graphql-go,这可以通过以下命令完成
go get github.com/graphql-go/graphql
接下来,我们描述产品的结构(以简化形式)
type Product struct { ID int64 `json:"id"` Name string `json:"name"` Info string `json:"info,omitempty"` Price float64 `json:"price"` }
ID
唯一标识符, Name
-名称, Info
-产品信息, Price
-价格
首先要做的是调用Do
方法,该方法接受数据方案并将查询参数作为输入参数。 它将把结果数据返回给我们(以进一步传输给客户)
result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, })
完整代码 func executeQuery(query string, schema graphql.Schema) *graphql.Result { result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) if len(result.Errors) > 0 { fmt.Printf("errors: %v", result.Errors) } return result } func main() { http.HandleFunc("/product", func(w http.ResponseWriter, r *http.Request) { result := executeQuery(r.URL.Query().Get("query"), schema) json.NewEncoder(w).Encode(result) }) http.ListenAndServe(":8080", nil) }
Schema
-数据方案, RequestString
查询字符串参数的值,在本例中为query
值
架构图
模式接受两种根数据类型: Query
-不可变数据, Mutation
-可变数据
var schema, _ = graphql.NewSchema( graphql.SchemaConfig{ Query: queryType, Mutation: mutationType, }, )
询问
Query
用于读取(并且仅读取)数据。 使用Query
我们指定服务器应返回什么数据。
我们将编写Query
数据类型的实现,在本例中,它将包含具有有关单个产品(产品)和商品列表(列表)的信息的字段
var queryType = graphql.NewObject( graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "product": &graphql.Field{ Type: productType, Description: "Get product by id",
queryType类型包含必需的Name
和Fields
以及可选的Description
(用于文档)
反过来,“ Fields
字段还包含必需的“ Type
字段和可选的Args
,“ Resolve
和“ Description
字段
Args(参数)
参数-从客户端传输到服务器并影响返回数据结果的参数列表。 参数绑定到特定字段。 并且参数可以在Query
和Mutation
传递。
?query={product(id:1){name,info,price}}
在这种情况下, product
字段的id
参数值为1表示必须返回具有指定标识符的产品。
对于list
省略list
参数,但在实际应用中可以是例如limit
和offset
。
解决(识别)
处理数据的所有逻辑(例如,数据库查询,处理和过滤)都在识别器中,由识别器返回数据,该数据将作为对请求的响应而传输到客户端。
型式
GraphQL使用其类型系统来描述数据。 您可以使用基本类型String
, Int
, Float
, Boolean
和您自己的(自定义)类型。 对于我们的示例,我们将需要一个自定义Product
类型,该类型将描述Product
所有属性
var productType = graphql.NewObject( graphql.ObjectConfig{ Name: "Product", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.Int, }, "name": &graphql.Field{ Type: graphql.String, }, "info": &graphql.Field{ Type: graphql.String, }, "price": &graphql.Field{ Type: graphql.Float, }, }, }, )
对于每个字段,都指定了基本类型,在这种情况下为graphql.Int
, graphql.String
, graphql.Float
。
嵌套字段的数量没有限制,因此您可以实现任何级别的图形系统。
变异
突变是这些可变数据,包括:添加,编辑和删除。 否则,变异与常规查询非常相似:它们也接受Args
参数,并返回Resolve
数据作为对查询的响应。
让我们为我们的产品编写变异。 var mutationType = graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ "create": &graphql.Field{ Type: productType, Description: "Create new product", Args: graphql.FieldConfigArgument{ "name": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.String),
都类似于queryType
。 只有一个小的特征类型graphql.NewNonNull(graphql.Int)
,它告诉我们该字段不能为空(类似于MySQL中的NOT NULL
)
仅此而已。 现在,我们有一个简单的Go CRUD API用于处理商品。 在此示例中,我们没有使用数据库,而是研究了如何创建数据模型并使用突变对其进行操作。
例子
如果您通过下载了源
go get github.com/graphql-go/graphql
只需使用示例进入目录
cd examples/crud
并运行该应用程序
go run main.go
您可以使用以下查询:
通过ID获取产品
http://localhost:8080/product?query={product(id:1){name,info,price}}
获取产品列表
http://localhost:8080/product?query={list{id,name,info,price}}
添加新产品
http://localhost:8080/product?query=mutation+_{create(name:"Tequila",info:"Strong alcoholic beverage",price:999){id,name,info,price}}
产品编辑
http://localhost:8080/product?query=mutation+_{update(id:1,price:195){id,name,info,price}}
通过ID删除产品
http://localhost:8080/product?query=mutation+_{delete(id:1){id,name,info,price}}
如果使用REST,请注意GraphQL作为可能的替代方法。 是的,乍看之下似乎比较困难,但是值得一开始,几天之内您就会掌握这项技术。 至少它将是有用的。