使用Apollo Client创建新用户时出现POST请求400错误
注册用户时POST 400错误排查与解决
问题现象
创建新用户时触发 POST http://localhost:4000/ 400(Bad Request) 错误,前端onError回调中的graphQLErrors未在控制台打印,但通过Apollo Studio运行同名Mutation却能正常执行。
网络响应明确提示:GraphQLError: Unknown argument "createUserInput" on field "Mutation.createUser"
相关代码
前端实现代码
const REGISTER_USER = gql` mutation Mutation( $createUser: CreateUserInput! ) { createUser(createUserInput: $createUserInput){ email name token password } } ` const Register = () => { const context = useContext(AuthContext) let navigate = useNavigate() const [errors, setErrors] = useState([]) function registerUserCallback() { console.log("Callback hit") registerUser() } const {onChange, onSubmit, values} = useForm(registerUserCallback, { name: '', email: '', password:'', confirmPassword: '', }) const [registerUser, {loading}] = useMutation(REGISTER_USER, { update(proxy, {data: {registerUser: userData}}) { context.login(userData) navigate('/Dashboard') }, onError({graphQLErrors}) { setErrors(graphQLErrors) console.log("Error: " + graphQLErrors) console.log(graphQLErrors) }, variables: {createUserInput: values} })
Apollo Client配置代码
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client"; import { setContext } from "@apollo/client/link/context"; const httpLink = createHttpLink({ uri: 'http://localhost:4000' }) const authLink = setContext((_, {headers}) => { return { headers: { ...headers, authorization: localStorage.getItem('token') || "" } } }) export const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() });
后端Mutation代码
@Mutation((returns) => User) async createUser(@Arg('data') data:CreateUserInput, @Ctx() ctx: Context) { const oldUser = await ctx.prisma.user.findFirst({ where: { email: data.email}}) if(oldUser) { throw new ApolloError('A user is already registered with the email' + data.email, 'USER_ALREADY_EXISTS') } var encryptedPassword = await bcrypt.hash(data.password, 10) const newUser = await ctx.prisma.user.create({ data: { name: data.name, email: data.email, password: encryptedPassword } }) return {token: jwt.sign(newUser, 'supersecret')} }
CreateUserInput代码
export class CreateUserInput { @Field((type) => String) name: string @Field((type) => String) email: string @Field((type) => String) password: string }
问题根源
- 参数名不匹配:后端Mutation声明接收的参数名为
data,但前端GraphQL请求中使用了createUserInput作为参数名,导致服务端无法识别参数 - 变量定义与传递不一致:前端Mutation中声明的变量是
$createUser,但调用时传递的变量是createUserInput: values - 返回字段不匹配:前端请求了
password字段,但后端并未返回该字段 - update回调字段错误:前端update函数中使用
registerUser获取返回数据,但后端Mutation的字段名是createUser
修复步骤
1. 修正前端GraphQL Mutation定义
将参数名改为data,去掉不存在的password请求字段:
const REGISTER_USER = gql` mutation Mutation( $data: CreateUserInput! ) { createUser(data: $data){ email name token } } `
2. 修正useMutation配置
- 对齐变量名与Mutation定义
- 修正update回调的字段名
- 过滤掉后端不需要的
confirmPassword字段:
const [registerUser, {loading}] = useMutation(REGISTER_USER, { update(proxy, {data: {createUser: userData}}) { context.login(userData) navigate('/Dashboard') }, onError(error) { // 打印完整错误信息便于排查 console.log("Full error: ", error) setErrors(error.graphQLErrors || []) }, variables: { data: { name: values.name, email: values.email, password: values.password } } })
内容的提问来源于stack exchange,提问作者Esore
相关产品推荐
相关产品推荐

