GraphQL & Go,graphql基本知识,go-graphql使用
Posted 尚墨1111
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GraphQL & Go,graphql基本知识,go-graphql使用相关的知识,希望对你有一定的参考价值。
GraphQL & Go
1 RESTful
1.1 基本概念
概念:Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。
功能
资源:互联网所有的事物都可以被抽象为资源.每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
1.2 HTTP VS REST
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get
http://127.0.0.1/item/queryItem?id=1 查询,GET
http://127.0.0.1/item/addItem新增,POST
http://127.0.0.1/item/updateItem 更新,POST
http://127.0.0.1/item/deleteItem?id=1 删除,GET或POST
使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
下面是一些例子。
GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
URL组成 : 协议://IP地址:端口/路径?参数1=值1&参数2=值2...
传统带参访问方式:
接口:/employees
访问路径 http://localhost:8080/employee?id=1&name=tom&age=23
使用参数路径访问方式:
接口:/employees/id/name/age
http://localhost:8080/employee/12/tom/23
2 GraphQL
学习:中文官网
背景:REST接口无法满足变化的需求,一遍就得重新改
GraphQL 服务:每个类型的每个字段都由一个 resolver 函数支持,当一个字段被执行时,相应的 resolver 被调用以产生下一个值。如果字段产生标量值,例如字符串或数字,则执行完成。如果一个字段产生一个对象,则该查询将继续执行该对象对应字段的解析器,直到生成标量值
例如这个查询:
me
name
会产生这样的JSON结果:
"me":
"name": "Luke Skywalker"
2.1 Fields 字段:请求参数
如果类型是object,就可以无限套娃
hero
name
# 查询可以有备注!
friends
name
"data":
"hero":
"name": "R2-D2",
"friends": [
"name": "Luke Skywalker"
,
"name": "Han Solo"
,
"name": "Leia Organa"
]
2.2 参数
2.2.1 给字段传递参数的能力,定参
在类似 REST 的系统中,你只能传递一组简单参数 —— 请求中的 query 参数和 URL 段。但是在 GraphQL 中,每一个字段和嵌套对象都能有自己的一组参数,从而使得 GraphQL 可以完美替代多次 API 获取请求
GraphQL 自带一组默认标量类型:
Int
:有符号 32 位整数。Float
:有符号双精度浮点值。String
:UTF‐8 字符序列。Boolean
:true
或者false
。ID
:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。
human(id: "1000")
name
height
2.2.2 变量:动态的参数
- 使用
$variableName
替代查询中的静态值。 - 声明
$variableName
为查询接受的变量之一。 - 将
variableName: value
通过传输专用(通常是 JSON)的分离的变量字典中
# "graphql": true, "variables": "episode": JEDI
query HeroNameAndFriends($episode: Episode)
hero(episode: $episode)
name
friends
name
2.2.3 元字段
你并不知道你将从 GraphQL 服务获得什么类型,这时候你就需要一些方法在客户端来决定如何处理这些数据。GraphQL 允许你在查询的任何位置请求 __typename
,一个元字段,以获得那个位置的对象类型名称
search(text: "an")
__typename
... on Human
name
"data":
"search": [
"__typename": "Human",
"name": "Han Solo"
2.3 请求类型
操作类型可以是 query、mutation 或 subscription
query HeroNameAndFriends
hero
name
friends
name
2.3.1 mutation:修改请求,类似post
# 定义
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!)
createReview(episode: $ep, review: $review)
stars
commentary
# 请求,相当于post
"ep": "JEDI",
"review":
"stars": 5,
"commentary": "This is a great movie!"
# response
"data":
"createReview":
"stars": 5,
"commentary": "This is a great movie!"
3 go-graphql
GO文档:https://pkg.go.dev/github.com/graphql-go/graphql
schema:定义了对象中的哪些字段是我们期望得到的
resolve:解析器函数,每个特定的field被请求时触发执行这个函数
3.1 schema
3.1.1 graphql.Field
graphql的操作逻辑单位,名字、描述、接收参数、返回参数、解析器
type Field struct
Name string `json:"name"` // used by graphlql-relay
Type Output `json:"type"`
Args FieldConfigArgument `json:"args"`
Resolve FieldResolveFn `json:"-"`
Subscribe FieldResolveFn `json:"-"`
DeprecationReason string `json:"deprecationReason"`
Description string `json:"description"`
var DoQueryTasks = &graphql.Field
Name: "Tasks list page",
Description: "query task list page",
Type: TaskListType, //返回类型(列表)
Args: taskArgsNoTaskManageId, //接收参数
Resolve: resolver.QueryTaskListPage, //处理解析器
3.1.2 输入参数定制
graphql.ArgumentConfig
,接收的参数只有类型,没有处理逻辑,所以对应的是config类,不需要嵌套Field
// 参数配置
type ArgumentConfig struct
Type Input `json:"type"`
DefaultValue interface `json:"defaultValue"`
Description string `json:"description"`
// 参数定义
type FieldConfigArgument map[string]*ArgumentConfig
// 实现了入参的定义
graphql.FieldConfigArgument
"id": &graphql.ArgumentConfigType: graphql.Int, Description: "任务ID",
"name": &graphql.ArgumentConfigType: graphql.String, Description: "姓名",
3.1.3 输出参数定制
graphql.NewObject
,嵌套里面还会有嵌套,所以需要套娃式Fields
Object类型,用于描述层级或者树形数据结构。对于树形数据结构来说,叶子字段的类型都是标量数据类型。几乎所有 GraphQL 类型都是对象类型。Object 类型有一个 name 字段,以及一个很重要的 fields 字段。fields 字段可以描述出一个完整的数据结构。
func NewObject(config ObjectConfig) *Object
type ObjectConfig struct
Name string `json:"name"`
Interfaces interface `json:"interfaces"`
Fields interface `json:"fields"`
IsTypeOf IsTypeOfFn `json:"isTypeOf"`
Description string `json:"description"`
// 定制输出结果
var TaskListType = graphql.NewObject(graphql.ObjectConfig
Name: "TaskListPage",
Fields: graphql.Fields
"total": &graphql.FieldType: graphql.Int, Description: "总数",
"list": &graphql.FieldType: graphql.NewList(OutPutType), Description: "数据列表",
)
var OutPutType = graphql.NewObject(graphql.ObjectConfig
Name: "OutPutType",
Fields: graphql.Fields
"id": &graphql.FieldType: graphql.Int, Description: "ID",
"createdAt": &graphql.FieldType: scalars.CustomTime,Description: "创建时间",
"createdBy": &graphql.FieldType: graphql.String,Description: "创建人",
"modifiedAt": &graphql.FieldType: scalars.CustomTime,Description: "修改时间",
"modifiedBy": &graphql.FieldType: graphql.String,Description: "修改人",
,
)
3.1.4 schema
graphql.SchemaConfig
type SchemaConfig struct
Query *Object
Mutation *Object
Subscription *Object
Types []Type
Directives []*Directive
Extensions []Extension
var Schema graphql.Schema
// init 初始化GraphQL
func init()
Schema, _ = graphql.NewSchema(graphql.SchemaConfig
Query: rootQuery,
Mutation: rootMutation,
)
// 查询操作graphql
var rootQuery = graphql.NewObject(
graphql.ObjectConfig
Name: "Query",
Fields: graphql.Fields
"tasks": schemas.DoQueryTasks, //查询任务列表
"users": schemas.DoQueryUsers, //查询用户列表
,
Description: "RootQuery",
,
)
// 修改操作graphql
var rootMutation = graphql.NewObject(
graphql.ObjectConfig
Name: "Mutation",
Fields: graphql.Fields
"updateTask": schemas.DoUpdateTask, //更新任务
"createTask": schemas.DoCreateTask, //创建任务
"deleteTask": schemas.DoDeleteTask, //删除任务
,
Description: "RootMutation",
,
)
3.2 解析器 ——处理函数
3.2.1 graphql.ResolveParams 透传的参数
// 请求结构
type ResolveParams struct
// Source is the source value
Source interface
// Args is a map of arguments for current GraphQL request
Args map[string]interface
// Info is a collection of information about the current execution state.
Info ResolveInfo
// Context argument is a context value that is provided to every resolve function within an execution.
// It is commonly
// used to represent an authenticated user, or request-specific caches.
Context context.Context
3.2.2 Resolve
// 绑定参数并解析
func QueryListById(p graphql.ResolveParams) (interface, error)
// 定义参数结构体
opts := entity.ListPageOptions
// 解析前端传递参数
jsonStr, _ := json.Marshal(p.Args)
if err := json.Unmarshal(jsonStr, &opts); err != nil
return nil, err
// 执行处理逻辑
list, total, err := service.QueryListPage(&opts)
if err != nil
return nil, err
// 返回前端所需结构
return dto.PageDataTotal: total, List: dto.GenListDTOs(list), nil
// 解析器会对应解析成输出的graphql结构
var ListType = graphql.NewObject(graphql.ObjectConfig
Name: "ListPage",
Fields: graphql.Fields
"total": &graphql.FieldType: graphql.Int, Description: "总数",
"list": &graphql.FieldType: graphql.NewList(OutPutType), Description: "数据列表",
)
3.3 路由控制
3.3.1 GraphqlHandler
graphql.Params、graphql.Do、graphql.Result
// 执行动作
func Do(p Params) *Result
// 执行结果
type Result struct
Data interface `json:"data"`
Errors []gqlerrors.FormattedError `json:"errors,omitempty"`
Extensions map[string]interface `json:"extensions,omitempty"`
// 参数的对齐
type Params struct
// The GraphQL type system to use when validating and executing a query.
Schema Schema
// A GraphQL language formatted string representing the requested operation.
RequestString string
// The value provided as the first argument to resolver functions on the top
// level type (e.g. the query object type).
RootObject map[string]interface
// A mapping of variable name to runtime value to use for all variables
// defined in the requestString.
VariableValues map[string]interface
// The name of the operation to use if requestString contains multiple
// possible operations. Can be omitted if requestString contains only
// one operation.
OperationName string
// Context may be provided to pass application-specific per-request
// information to resolve functions.
Context context.Context
3.3.2 对接前端
// graphql请求
query HeroNameAndFriends
hero(id:1001)
name
friends
name
// QueryRequest GraphQL 查询语法字段
type QueryRequest struct
Query string `json:"query" form:"query"` //GraphQL query 语句
Variables map[string]interface `json:"variables" form:"variables"` //变量
func GraphQLHandler(c *gin.Context)
var reqData dto.QueryRequest
if err := c.Bind(&reqData); err != nil
return
//解析参数
result := graphql.Do(graphql.Params
Schema: schema.Schema,
RequestString: reqData.Query,
Context: c,
VariableValues: reqData.Variables,
)
if result.HasErrors()
return
httprsp.Success(c, result.Data)
3.4 执行流程
3.5 文件结构
|
|---facade
| |-router
| |-controller
|
|--assembler
| |-schema:定义Fields、入参、出参
| |-resolver:定义解析器逻辑
以上是关于GraphQL & Go,graphql基本知识,go-graphql使用的主要内容,如果未能解决你的问题,请参考以下文章