上一篇咱们实现了几乎所有的数据库访问代码。这一次咱们进一步实现 GraphQL 接口封装。
一、GraphqQL 模式建立
- 基础模式:
var baseType = graphql.NewObject(graphql.ObjectConfig{ Name: "Base", Fields: graphql.Fields{ "id": &graphql.Field{Type: graphql.ID}, "created_at": &graphql.Field{Type: graphql.DateTime}, "updated_at": &graphql.Field{Type: graphql.DateTime}, "deleted_at": &graphql.Field{Type: graphql.DateTime}, }, Description: "baseType", })
基础维度模式:
var baseDimensionType = graphql.NewObject(graphql.ObjectConfig{ Name: "BaseDimension", Fields: graphql.Fields{ "name": &graphql.Field{Type: graphql.String}, "category": &graphql.Field{Type: graphql.String}, "content": &graphql.Field{Type: graphql.String}, "tag": &graphql.Field{Type: graphql.String}, }, Description: "baseDimensionType", })
账号模式:
var userType = graphql.NewObject(graphql.ObjectConfig{ Name: "User", Fields: graphql.Fields{ "account": &graphql.Field{Type: graphql.String}, "password": &graphql.Field{Type: graphql.String}, "time_account_change_latest": &graphql.Field{Type: graphql.DateTime}, "time_login_one": &graphql.Field{Type: graphql.DateTime}, "time_login_second": &graphql.Field{Type: graphql.DateTime}, "base": &graphql.Field{Type: baseType}, "dimension_readings": &graphql.Field{Type: graphql.NewList(dimensionReadingType)}, "dimension_writings": &graphql.Field{Type: graphql.NewList(dimensionWritingType)}, "dimension_photos": &graphql.Field{Type: graphql.NewList(dimensionPhotoType)}, "eco_comments": &graphql.Field{Type: graphql.NewList(ecoCommentType)}, "system_ads": &graphql.Field{Type: graphql.NewList(systemAdType)}, "bind_profiles": &graphql.Field{Type: graphql.NewList(bindProfileType)}, }, Description: "userType", })
维度模式(例如:阅读金句):
var dimensionReadingType = graphql.NewObject(graphql.ObjectConfig{ Name: "DimensionReading", Fields: graphql.Fields{ "author": &graphql.Field{Type: graphql.String}, "location": &graphql.Field{Type: graphql.String}, "base_dimension": &graphql.Field{Type: baseDimensionType}, "eco_comments": &graphql.Field{Type: graphql.NewList(ecoCommentType)}, "users": &graphql.Field{Type: graphql.NewList(userType)}, }, Description: "dimensionReadingType", })
生态模式(例如:评论):
var ecoCommentType = graphql.NewObject(graphql.ObjectConfig{ Name: "EcoComment", Fields: graphql.Fields{ "data": &graphql.Field{Type: graphql.String}, "is_published": &graphql.Field{Type: graphql.Boolean}, "base": &graphql.Field{Type: baseType}, }, Description: "ecoCommentType", })
二、GraphQL 端点(Endpoint)建立
- Endpoint构建,以维度为例(其他的都类似):
var EndpointGetDimensionReading = &graphql.Field{ Type: responseDimensionReadingType, Args: graphql.FieldConfigArgument{ "from_id": &graphql.ArgumentConfig{Type: graphql.NewNonNull(graphql.String)}, "from_nickname": &graphql.ArgumentConfig{Type: graphql.NewNonNull(graphql.String)}, "content": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.String), Description: "query by cond", }, }, Resolve: func(p graphql.ResolveParams) (i interface{}, err error) { var entities []DimensionReading var count int64 content, contentOk := p.Args["content"].(string) fromId, fromIdOk := p.Args["from_id"].(string) fromNickname, fromNicknameOK := p.Args["from_nickname"].(string) if !contentOk || !fromIdOk || !fromNicknameOK || fromId == "" || fromNickname == "" || content == "" { return nil, errors.New("required id,name,content") } var condGetDetails CondGetDetails if !contentOk { return nil, errors.New("参数解析失败") } err = json.Unmarshal([]byte(content), &condGetDetails) if err != nil { return nil, errors.New("参数解析失败") } result, err := GetEntities(condGetDetails) if err != nil { return nil, err } err = result.Preload(clause.Associations).Find(&entities).Count(&count).Error return ResponseCommon{ Code: 200, Content: entities, Count: count, Msg: Message{ Success: "success", }, }, err }, }
- 每个接口访问时,除了接口必要的参数数据之外,还附带上额外的用户数据(id和nickname),方便以后的审计
- content是接口必要的参数数据,使用的是前面的文章中设计好的数据结构
- 博客系统的所有接口参数尽量保持一致——这是一个能简化逻辑的约定。
- GraphQL 的 endpoint 接入到 Gin 框架内:
var queryType = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "dimensionReading": EndpointGetDimensionReading, //获取参展项目列表 }, }) var Schema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: queryType, //Mutation: mutationType, }) func ExecuteQuery(schema graphql.Schema, query string, variables map[string]interface{}, operationName string) *graphql.Result { result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, VariableValues: variables, OperationName: operationName, }) if len(result.Errors) > 0 { log.Printf("errors:%s", result.Errors) } return result }
Gin 框架与 GraphQL 的中间连接代码
func RouterDimension(router *gin.Engine) (interface{}, error) { routerDimension := router.Group("/blog/x") { routerDimension.POST("/v1", func(c *gin.Context) { var query Query err := c.BindJSON(&query) if err != nil { log.Println(err) c.JSON(http.StatusOK, err) return } result := models.ExecuteQuery(models.Schema, query.Query, query.Variables, query.OperationName) // 此处连接GraphQL c.JSON(http.StatusOK, result) }) } return routerDimension, nil }
Gin 路由相关代码实现。
 
                             
                 
                