Golang+Gorm+GraphQL创建用户报错invalid input问题排查
问题:Golang+Gorm+PostgreSQL开发GraphQL服务,createuser mutation返回"invalid input"错误
使用Golang结合Gorm、PostgreSQL开发GraphQL服务,调用http://localhost:8080/graphql执行createuser mutation时无法创建用户,返回"invalid input"错误。以下是相关代码、请求示例及返回结果:
完整代码片段
基础定义与User模型
package main import ( "fmt" "log" "net/http" "time" "github.com/graphql-go/graphql" "github.com/graphql-go/handler" "github.com/kaleabbyh/foodrecipie/config" _ "github.com/lib/pq" ) // Note: 表users已通过独立迁移代码成功创建,包含User模型属性 type User struct { ID int `gorm:"type:int;primary_key;identity(100,1)"` Name string `gorm:"type:varchar(255);not null"` Email string `gorm:"uniqueIndex;not null"` Password string `gorm:"not null"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } func checkErr(err error) { if err != nil { panic(err) } } func main() { config, err := Connection.LoadConfig(".") if err != nil { log.Fatal("? Could not load environment variables", err) } Connection.ConnectDB(&config) db:=Connection.DB userType := graphql.NewObject(graphql.ObjectConfig{ Name: "User", Description: "An user", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Resolve: func(p graphql.ResolveParams) (interface{}, error) { if user, ok := p.Source.(*User); ok { return user.Name, 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 { return user.Email, nil } return nil, nil }, }, "password": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Resolve: func(p graphql.ResolveParams) (interface{}, error) { if user, ok := p.Source.(*User); ok { return user.Email, nil } return nil, nil }, }, }, })
Root Mutation定义
rootMutation := graphql.NewObject(graphql.ObjectConfig{ Name: "RootMutation", Fields: graphql.Fields{ "createuser":&graphql.Field{ Type: 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) { input, ok := params.Args["input"].(map[string]interface{}) fmt.Println(input) if !ok { return nil, fmt.Errorf("invalid input") } name, _ := input["name"].(string) email, _ := input["email"].(string) password, _ := input["password"].(string) user := User{ Name:name, Email :email, Password:password, } err := db.Create(&user).Error if err != nil { return nil, err } return user, nil }, }, }, })
Root Query与Schema定义
rootQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "RootQuery", Fields: graphql.Fields{ "users": &graphql.Field{ Type: graphql.NewList(userType), Description: "List of users.", Resolve: func(p graphql.ResolveParams) (interface{}, error) { var users []User err := db.Find(&users).Error checkErr(err) fmt.Println(users) return users, nil }, }, }, }) schema, _ := graphql.NewSchema(graphql.SchemaConfig{ Query: rootQuery, Mutation: rootMutation, }) h := handler.New(&handler.Config{ Schema: &schema, Pretty: true, GraphiQL: true, }) // 启动HTTP服务 http.Handle("/graphql", h) fmt.Println("server is running on port: 8080") http.ListenAndServe(":8080", nil) }
请求示例
mutation { createuser( name: "kaleab", email: "user@example.com", password: "random") { name } }
返回结果
{ "data": { "createuser": null }, "errors": [ { "message": "invalid input", "locations": [ { "line": 2, "column": 3 } ], "path": [ "createuser" ] } ] }
错误原因
- 参数获取逻辑不匹配:你的
createuserResolve函数尝试从params.Args["input"]获取参数,但实际在Mutation的Args定义里,你把name、email、password作为了顶级参数,并没有封装在input对象中;同时你的请求也是直接传递顶级参数,导致params.Args["input"]不存在,类型断言失败返回错误。 - 字段Resolve错误:
userType中的password字段Resolve函数错误返回了user.Email,应该返回user.Password。
修复方案
方案1:直接获取顶级参数(匹配当前请求格式)
修改createuser的Resolve函数,直接从params.Args中读取顶级参数:
Resolve: func(params graphql.ResolveParams) (interface{}, error) { name, okName := params.Args["name"].(string) email, okEmail := params.Args["email"].(string) password, okPwd := params.Args["password"].(string) // 校验参数类型合法性 if !okName || !okEmail || !okPwd { return nil, fmt.Errorf("invalid input") } user := User{ Name: name, Email: email, Password: password, } err := db.Create(&user).Error if err != nil { return nil, err } return user, nil },
方案2:改用Input对象(更规范的GraphQL实践)
如果想使用input参数的方式,需要先定义Input类型,再调整Mutation和请求格式:
- 定义UserInput类型
userInputType := graphql.NewInputObject(graphql.InputObjectConfig{ Name: "UserInput", Fields: graphql.InputObjectConfigFieldMap{ "name": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String), }, "email": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String), }, "password": &graphql.InputObjectFieldConfig{ Type: graphql.NewNonNull(graphql.String), }, }, })
- 修改createuser的Args定义
Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(userInputType), }, },
- 调整请求格式
mutation { createuser(input: { name: "kaleab", email: "user@example.com", password: "random" }) { name } }
额外修复:修正password字段的Resolve函数
"password": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Resolve: func(p graphql.ResolveParams) (interface{}, error) { if user, ok := p.Source.(*User); ok { return user.Password, nil // 替换原错误的user.Email } return nil, nil }, },
内容的提问来源于stack exchange,提问作者kaleab
相关产品推荐
相关产品推荐

