【问题标题】:GraphQl Mutation: addUser not creating userGraphQl 突变:addUser 不创建用户
【发布时间】:2021-11-24 13:27:07
【问题描述】:

我正在将一个 Google Books 应用从 Restful API 重构为 GraphQL,但我遇到了一个不符合我预期的突变。

当用户填写 Signup.js 上的表单时,Mutation ADD_USER 应该在 Mongoose 中创建一个用户,该用户应该有一个 JWT 令牌分配给他们,并且用户应该在成功执行 Mutation 后登录。

观察到的动作: • 突变是从前端发射的。当我在浏览器中打开开发人员工具时,我可以看到用户名、电子邮件和密码作为变量传递。 • 我已尝试在控制台记录令牌,但一直收到未定义的返回 • 当我尝试在 GraphQL 沙箱中运行突变时,我得到一个空值返回。 • 当我控制台记录resolvers.js 中的args 时,控制台上没有出现任何值,这告诉我请求没有到达解析器。

SignupForm.js(React FE 页面)

import React, { useState } from "react";
import { Form, Button, Alert } from "react-bootstrap";
import { useMutation } from "@apollo/client";
import { ADD_USER } from "../utils/mutations";
import Auth from "../utils/auth";

const SignupForm = () => {
  // set initial form state
  const [userFormData, setUserFormData] = useState({
    username: "",
    email: "",
    password: "",
  });
  // set state for form validation
  const [validated] = useState(false);
  // set state for alert
  const [showAlert, setShowAlert] = useState(false);

  const [addUser] = useMutation(ADD_USER);

  const handleInputChange = (event) => {
    const { name, value } = event.target;
    setUserFormData({ ...userFormData, [name]: value });
  };

  const handleFormSubmit = async (event) => {
    event.preventDefault();

    // check if form has everything (as per react-bootstrap docs)
    const form = event.currentTarget;
    if (form.checkValidity() === false) {
      event.preventDefault();
      event.stopPropagation();
    }

    try {
      ///Add user is not returning data. payload is being passed as an object

      const response = await addUser({
        variables: { ...userFormData },
      });

      if (!response.ok) {
        throw new Error("OH NO!SOMETHING WENT WRONG!");
      }

      const { token, user } = await response.json();
      console.log(user);
      Auth.login(token);
    } catch (err) {
      console.error(err);
      setShowAlert(true);
    }

    setUserFormData({
      username: "",
      email: "",
      password: "",
    });
  };

Mutation.js

export const ADD_USER = gql`
  mutation addUser($username: String!, $email: String!, $password: String!) {
    addUser(username: $username, email: $email, password: $password) {
      token
      user {
        username
        email
      }
    }
  }
`;

typeDefs.js

const { gql } = require("apollo-server-express");

const typeDefs = gql`
  input SavedBooks {
    authors: [String]
    description: String
    bookId: String
    image: String
    link: String
    title: String
  }
  type Books {
    authors: [String]
    description: String
    bookId: ID
    image: String
    link: String
    title: String
  }
  type User {
    _id: ID
    username: String
    email: String
    password: String
    savedBooks: [Books]
  }
  type Auth {
    token: ID!
    user: User
  }
  type Query {
    me: User
  }
  type Mutation {
    ##creates a user profile through the Auth type, that way we can pass a token upon creation
    addUser(username: String!, email: String!, password: String!): Auth

    login(email: String!, password: String!): Auth

    saveBook(bookData: SavedBooks): User

    deleteBook(bookId: ID!): User
  }
`;
module.exports = typeDefs;

resolvers.js

const { User, Book } = require("../models");
const { AuthenticationError } = require("apollo-server-express");
const { signToken } = require("../utils/auth");


const resolvers = {
  Query: {
    me: async (parent, args, context) => {
      if (context.user) {
        return User.findOne({ _id: context.user._id }).populate("books");
      }

      throw new AuthenticationError("You need to log in");
    },
  },
};
Mutation: {
  //try refactoring as a .then
  addUser: async (parent, args) => {
    //create user profile
    await console.log("resolver test");
    console.log(args);
    const user = await User.create({ username, email, password });
    //assign token to user
    const token = signToken(user);
    return { token, user };
  };

  login: async (parent, { email, password }) => {
    const user = User.findOne({ email });
    if (!user) {
      throw new AuthenticationError("Invalid Login Credentials");
    }
    const correctPw = await profile.isCorrectPassword(password);
    if (!correctPw) {
      throw new AuthenticationError("Invalid Login Credentials");
    }
    const token = signToken(user);
    return { token, user };
  };

  saveBook: async (parent, { bookData }, context) => {
    if (context.user) {
      return User.findOneAndUpdate(
        { _id: context.user._id },
        { $addToSet: { savedBooks: bookData } },
        { new: true }
      );
    }
    throw new AuthenticationError("You need to log in");
  };

  deleteBook: async (parent, { bookId }, context) => {
    if (context.user) {
      return User.findOneAndUpdate(
        { _id: contex.user._id },
        //remove selected books from the savedBooks Array
        { $pull: { savedBooks: context.bookId } },
        { new: true }
      );
    }
    throw new AuthenticationError("You need to log in");
  };
}
module.exports = resolvers;

auth.js

const jwt = require("jsonwebtoken");

// set token secret and expiration date
const secret = "mysecretsshhhhh";
const expiration = "2h";

module.exports = {
  // function for our authenticated routes
  authMiddleware: function ({ req }) {
    // allows token to be sent via  req.query or headers
    let token = req.query.token || req.headers.authorization || req.body.token;

    // ["Bearer", "<tokenvalue>"]
    if (req.headers.authorization) {
      token = token.split(" ").pop().trim();
    }

    if (!token) {
      return req;
    }

    // verify token and get user data out of it
    try {
      const { data } = jwt.verify(token, secret, { maxAge: expiration });
      req.user = data;
    } catch {
      console.log("Invalid token");
      return res.status(400).json({ message: "invalid token!" });
    }

    // send to next endpoint
    return req;
  },
  signToken: function ({ username, email, _id }) {
    const payload = { username, email, _id };

    return jwt.sign({ data: payload }, secret, { expiresIn: expiration });
  },
};

基本上,我已经从前端梳理到后端,寻找我在哪里引入了这个错误,并被卡住了。非常感谢任何建议或反馈。

【问题讨论】:

  • 在 FE 编码之前让它在操场上工作(使用查询变量)
  • 我将把更多的精力集中在操场上,您是否看到我正在运行的突变 (mutation.js) 中有任何会导致返回的内容? { "data": { "addUser": null } } 全新的开发者,甚至在 GraphQL 上更新
  • 确定... API/BE 日志记录您正在使用服务器控制台进行测试,而不是在浏览器/FE 上...您是否看到任何 BE 消息(来自身份验证/中间件、启动服务器、其他解析器参数)?
  • 正确,我正在使用服务器控制台尝试验证用户提交表单后在 BE 上收到的参数。我没有收到任何消息。在 resolvers.js 和 addUser Mutation 中,我尝试了 console.log("resolver test) 和 console.log(args),但在服务器控制台上没有收到任何消息。
  • 不要重复自己,我们从问题/描述中知道...我建议了其他一些事情/测试

标签: javascript reactjs graphql


【解决方案1】:

我能够找出问题所在。首先,resolver.js 上的语法错误导致我的突变无法被读取。

接下来,我对 SignupForm.js 上的 handleFormSubmit 做了如下调整

  try {
      ///Add user is not returning data. payload is being passed as an object

      const {data} = await addUser({
        variables: { ...userFormData },
      });
     console.log(data)
      console.log(userFormData)

  
      **Auth.login(data.addUser.token);**
    } catch (err) {
      console.error(err);
      setShowAlert(true);
    }

这样,我的 FE 正确地说明了我的 Auth 中间件在成功创建用户后传回的内容。感谢您的帮助 xadm,能够把这件事说出来让我开始思考还有什么地方可以攻击这个错误。

【讨论】:

    猜你喜欢
    • 2019-07-26
    • 2019-11-21
    • 2018-09-19
    • 1970-01-01
    • 2022-10-23
    • 2018-09-22
    • 2019-01-31
    • 2018-01-12
    • 2020-07-15
    相关资源
    最近更新 更多