You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GraphQL Mutation报400错误的原因排查求助

问题:GraphQL Mutation请求400错误,Resolver未执行

我尝试将前端useState中的变量通过GraphQL Mutation传给后端Mongoose API,保存到MongoDB,但始终收到POST http://localhost:4000/graphql 400 (Bad Request)错误,服务端Resolver里的打印语句完全没执行。相关代码如下:

前端:frontend/new-post/page.tsx

const ADD_POST = gql`
  mutation CreatePost($post: PostInput!) {
    createPost(post: $post) {
      post
    }
  }
`;

export default function page() {
  const [createPost, {data, loading, error}] = useMutation(ADD_POST)
  const [post, setPost] = useState<IPost>({
    contactInfo: {
      phone: "",
      email: "",
      sns: {
        type: "Twitter",
        username: ""
      }
    },
    title: "",
    description: "",
})

  const handleSubmit = async () => {
      //Send "/api/new-post" to process post variable
      const { data } = await axios.post("/api/new-post", { post: post });
      console.log("NewPost ", data)
      console.log("NewPost ", data.post)
      // Works up until here
      await createPost({variables: {post: data.post} })
      router.push('/')
    }catch(err: any){
      console.log(err.message)
    }
  };
  

       //setPost function, onChangeHandler and Inputs for each fields here...

    <button
      type="button"
      onClick={()=>handleSubmit()}>
        Click
    </button>

后端:backend/src/PosttypeDef.ts

export const postTypeDefs = `#graphql

  scalar JSON

  type Post {
    _id: ID!
    contactInfo: JSON
    title: String!
    description: String!
  }

  type Query {
    posts: [Post!]!
    }
    

  type CreatePostResponse {
    success: Boolean!
    error: String
  }

  type Mutation {
    createPost(post: PostInput): String
  }

  input PostInput {
    contactInfo: JSON
    title: String!
    description: String!
  }
`;

后端:backend/post-resolver.ts

const dateScalar = new GraphQLScalarType({

export const postResolvers = {
  JSON: GraphQLJSON,

  Query: {
    // Return all posts
    posts: async () => {
      try {
        await connectDB();
        const posts = await Post.find();
        return posts;
      } catch (err) {
        console.log(err);
      }
    },
   

    //Return posts by User's ObjectId
    postsByUserId: async (parent, args) => {
      const { postedBy } = args;
      await connectDB();
      const posts = await Post.find();
      return posts.filter((post) => post.postedBy.toString() === postedBy);
    }
  },

  Mutation: {
    createPost: async (parent, args)=>{
      try{
        const {post} = args;
        // Just want to make this console.log work
        console.log("API endpoint", post)
        //Add to Mongodb, logic follows...
        return { success: true };

      }catch(err){
        return { success: false, error: err.toString() };
      }
    }
  }

};

Mongoose Schema

import mongoose from 'mongoose';

const postSchema = new mongoose.Schema({
  contactInfo: {
    phone: { type: String, default: '' },
    email: { type: String, default: '' },
    sns: {
      type: {
        type: String,
        default: 'Twitter'
      },
      username: { type: String, default: '' }
    }
  },
  title: { type: String, required: true },
  description: { type: String, default: '' },

});


const Post = mongoose.model('Post', postSchema);

export default Post;

问题原因及修复步骤

1. GraphQL类型定义与Resolver返回值不匹配(核心错误)

  • 后端PosttypeDef.ts中,Mutation的createPost定义返回String,但Resolver实际返回的是{ success: Boolean, error: String }对象,完全不符合类型约定,导致GraphQL请求校验失败,直接返回400错误。
  • 前端Mutation请求的返回字段是post,但后端根本没定义该返回字段,进一步加剧不匹配。

修复:

  • 修改后端PosttypeDef.ts的Mutation定义,让返回类型与Resolver一致:
type Mutation {
  createPost(post: PostInput!): CreatePostResponse!
}
  • 修改前端ADD_POST的Mutation请求,匹配后端返回字段:
const ADD_POST = gql`
  mutation CreatePost($post: PostInput!) {
    createPost(post: $post) {
      success
      error
    }
  }
`;

2. PostInput必填字段校验失败

后端PostInput中title是String!(必填),但前端初始post对象中title是空字符串,若用户未输入标题就提交,会触发GraphQL必填字段校验,返回400错误。

修复:

  • 在前端handleSubmit中添加校验,确保title不为空再提交:
const handleSubmit = async () => {
  if (!post.title.trim()) {
    console.log('标题不能为空');
    return;
  }
  // 后续逻辑...
};

3. Resolver中缺失实际创建文档的逻辑

当前Resolver仅返回success: true,未实际连接数据库并创建Post文档,即使请求成功也不会保存数据。

修复:
补充创建文档的逻辑:

Mutation: {
  createPost: async (parent, args)=>{
    try{
      const {post} = args;
      console.log("API endpoint", post);
      await connectDB();
      const newPost = new Post(post);
      await newPost.save();
      return { success: true };
    }catch(err){
      return { success: false, error: err.toString() };
    }
  }
}

4. 冗余的axios请求(可选优化)

前端handleSubmit中先调用axios.post("/api/new-post")处理post,再调用GraphQL Mutation,逻辑重复。若/api/new-post无必要预处理逻辑,可直接将post变量传给createPost,去掉axios请求:

const handleSubmit = async () => {
  if (!post.title.trim()) {
    console.log('标题不能为空');
    return;
  }
  try {
    await createPost({ variables: { post } });
    router.push('/');
  } catch (err: any) {
    console.log(err.message);
  }
};

内容的提问来源于stack exchange,提问作者kawa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:35:22