使用 graph-gophers/graphql-go 包的 graphql 突变查询错误

graphql mutation query error using graph-gophers/graphql-go package

问题

下面的突变

mutation {
  signUp(signUpInput: {email: "newuser@gmail.com", username: "newUser", password: "asdfasdfawerawer"}) {
    email
    username
  }
}

错误如下

{
    "errors": [
        {
            "message": "Cannot query field \"email\" on type \"SignUpResponse\".",
            "locations": [
                {
                    "line": 3,
                    "column": 5
                }
            ]
        },
        {
            "message": "Cannot query field \"username\" on type \"SignUpResponse\".",
            "locations": [
                {
                    "line": 4,
                    "column": 5
                }
            ]
        }
    ]
}

预期

{
  "data": {
    "signUp": {
      "email": "newuser@gmail.com",
      "username": "newUser"
    }
  }
}

代码片段

schema.graphql 片段

...

input SignUpInput {
  username: String!
  email: String!
  password: String!
}

type Mutation {
  signUp(signUpInput: SignUpInput): SignUpResponse!
}

type SignUpResponse {
  ok: Boolean!
  error: String
  addedUser: User
}

resolvers.go 片段

...

// UserResolver ingests properties from User
type UserResolver struct{ u *User }

// UserID returns the userId of the user
func (r *UserResolver) UserID() graphql.ID {
    return r.u.UserID
}

// Username returns the username of the user
func (r *UserResolver) Username() string {
    return r.u.Username
}

// Email returns the email of the user
func (r *UserResolver) Email() string {
    return r.u.Email
}

// Password returns the password of the user
func (r *UserResolver) Password() string {
    return r.u.Password
}

type SignUpArgs struct {
    Username string
    Email    string
    Password string
}

// SignUp returns a new User from Db and its responses
func (r *RootResolver) SignUp(args struct{ SignUpInput *SignUpArgs }) (*SignUpResolver, error) {
    // Find user:
    u, err := r.Db.CreateUser(args.SignUpInput)
    // need to deal with this different, so sort of error if we can't create the user
    // a. user already exists
    // b. email already exists
    if err != nil {
        // error creating the user
        msg := "already signed up"
        return &SignUpResolver{
            Status: false,
            Msg:    &msg,
            User:   nil,
        }, err
    }

    return &SignUpResolver{
        Status: true,
        Msg:    nil,
        User:   &UserResolver{&u},
    }, nil
}

// SignUpResolver is the response type
type SignUpResolver struct {
    Status bool
    Msg    *string
    User   *UserResolver
}

// Ok for SignUpResponse
func (r *SignUpResolver) Ok() bool {
    return r.Status
}

// Error for SignUpResponse
func (r *SignUpResolver) Error() *string {
    return r.Msg
}

// AddedUser for SignUpResponse
func (r *SignUpResolver) AddedUser() *UserResolver {
    return r.User
}

postgres.go - 数据库操作

// User returns a single user
func (d *Db) User(uid graphql.ID) (User, error) {
    var (
        sqlStatement = `SELECT * FROM users WHERE user_id=;`
        row          *sql.Row
        err          error
        u            User
    )
    row = d.QueryRow(sqlStatement, uid)
    err = row.Scan(
        &u.UserID,
        &u.Username,
        &u.Email,
        &u.Password,
    )
    util.Check(err, "row.Scan")
    return u, nil
}

// CreateUser - inserts a new user
func (d *Db) CreateUser(i *SignUpArgs) (User, error) {
    var (
        sqlStatement = `
            INSERT INTO users (email, username, password)
            VALUES (, , )
            RETURNING user_id`
        userID graphql.ID
        row    *sql.Row
        err    error
        u      User
    )
    /***************************************************************************
        * retrieve the UserID of the newly inserted record
        * db.Exec() requires the Result interface with the
                LastInsertId() method which relies on a returned value from postgresQL
        * lib/pq does not however return the last inserted record
    ****************************************************************************/
    row = d.QueryRow(sqlStatement, i.Email, i.Username, i.Password)
    if err = row.Scan(&userID); err != nil {
        // err: username or email is not unqiue --> user already exsits
        return u, err
    }

    u, _ = d.User(userID)
    return u, nil
}

我已经尝试将 CreateUser 更改为此

// CreateUser - inserts a new user
func (d *Db) CreateUser(i *SignUpArgs) (User, error) {
    var (
        sqlStatement = `
            INSERT INTO users (email, username, password)
            VALUES (, , )
            RETURNING user_id`
        userID graphql.ID
        row    *sql.Row
        err    error
        u      User
    )
    /***************************************************************************
        * retrieve the UserID of the newly inserted record
        * db.Exec() requires the Result interface with the
                LastInsertId() method which relies on a returned value from postgresQL
        * lib/pq does not however return the last inserted record
    ****************************************************************************/
    row = d.QueryRow(sqlStatement, i.Email, i.Username, i.Password)
    if err = row.Scan(&userID); err != nil {
        // err: username or email is not unqiue --> user already exsits
        return u, err
    }
    err = row.Scan(
        &u.UserID,
        &u.Username,
        &u.Email,
        &u.Password,
    )
    util.Check(err, "row.Scan User")
    return u, nil
}

显然没有做到。因此问题是,为什么查询错误?似乎 UserResolver 不能 return User 数据,前提是该行是从数据库 return 编辑的。

您的类型定义包括:

type Mutation {
  signUp(signUpInput: SignUpInput): SignUpResponse!
}

type SignUpResponse {
  ok: Boolean!
  error: String
  addedUser: User
}

您似乎正在尝试查询 returned User 的字段,但 signUp 没有 return 一个 User 对象。相反,signUp return 是一个 SignUpResponse 对象,如错误所述,该对象没有任何名为 emailusername.

的字段

正确的查询应该是这样的:

mutation {
  signUp(signUpInput: {email: "newuser@gmail.com", username: "newUser", password: "asdfasdfawerawer"}) {
    addedUser {
      email
      username
    }
    ok
    error
  }
}