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
相关产品推荐
相关产品推荐

