React Apollo GraphQL Mutation returns 400(错误请求)
React Apollo GraphQL Mutation returns 400 (bad request)
我对 React Apollo 和 graphQL 还很陌生。我正在尝试创建一个编辑个人资料表单,将数据添加到用户个人资料中。当我点击提交时没有任何反应并在控制台日志中得到错误:
理想情况下,我希望表单最初呈现用户之前输入的任何数据,以便在提交表单并且他们没有更改所有输入时,他们没有更改的输入也不会在 mongoDB 数据库中被覆盖。
所有和任何建议将不胜感激!谢谢你!
- POST http://localhost:3000/graphql 400(错误请求)
[GraphQL 错误]:消息:未定义变量“$email”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$locationCity”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$locationState”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$locationCountry”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$interests”。位置:[object 对象],[object 对象],路径:未定义
- [网络错误]:ServerError:响应不成功:收到状态代码 400
在我的 schema.js 中,我有以下内容:
editOtherProfileDetails(email: String!, locationCity: String!, locationState: String!, locationCountry: String!, interests: String!): User
在我的 resolvers.js 中,我有以下内容:
editOtherProfileDetails: async (root, { email, locationCity, locationState, locationCountry, interests }, { User }) => {
const user = await User.findOneAndUpdate({ email },
{ $set: { locationCity: locationCity } },
{ $set: { locationState: locationState } },
{ $set: { locationCountry: locationCountry } },
{ $set: { interests: interests } },
{ new: true }
);
if (!user) {
throw new Error('User Not Found');
}
return user;
},
在我的 index.js 我有:
export const EDIT_OTHER_PROFILE_DETAILS = gql`
mutation($locationCountry: String!){
editOtherProfileDetails(email: $email, locationCity: $locationCity, locationState: $locationState, locationCountry: $locationCountry, interests: $interests){
email
locationCity
locationState
locationCountry
interests
}
}
`;
在我的 editProfile.js 中,我有以下内容:
import React, { Fragment } from 'react';
import { Mutation } from 'react-apollo';
import {GET_USER_PROFILE, EDIT_OTHER_PROFILE_DETAILS, PROFILE_PAGE } from './../../queries';
import { withRouter } from 'react-router-dom';
import toastr from 'toastr';
const initialState = {
locationCity: '',
locationState: '',
locationCountry: '',
interests: '',
error: ''
}
class EditOtherProfileMutations extends React.Component {
constructor(props) {
super(props);
this.state = {
locationCity: '',
locationState: '',
locationCountry: '',
interests: '',
error: ''
}
}
componentDidMount() {
if (this.props.profile) {
this.setState({
locationCity: this.props.profile.locationCity,
locationState: this.props.profile.locationState,
locationCountry: this.props.profile.locationCountry,
interests: this.props.profile.interests
});
}
toastr.options = {
"closeButton": false,
"debug": false,
"newestOnTop": true,
"progressBar": true,
"positionClass": "toast-bottom-right",
"preventDuplicates": false,
"onclick": null,
"showDuration": "300",
"hideDuration": "1000",
"timeOut": "5000",
"extendedTimeOut": "1000",
"showEasing": "swing",
"hideEasing": "linear",
"showMethod": "fadeIn",
"hideMethod": "fadeOut"
}
}
handleChange(event) {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value.charAt(0).toUpperCase() + value.substr(1).toLowerCase()
});
}
handleSubmit(event, editOtherProfileDetails) {
event.preventDefault();
editOtherProfileDetails().then(async () => {
toastr.success('We have updated your details!', 'Saved!');
}).catch(error => {
this.setState({
error: error.graphQLErrors.map(x => x.message)
})
// console.error("ERR =>", error.graphQLErrors.map(x => x.message));
});
}
render() {
const { locationCity, locationState, locationCountry, interests } = this.state
const userName = this.props.session.getCurrentUser.userName;
this.state;
return (
<Fragment>
<Mutation
mutation={EDIT_OTHER_PROFILE_DETAILS}
variables={{ email: this.props.session.getCurrentUser.email, locationCity, locationState, locationCountry, interests }}
refetchQueries={() => [
{ query: GET_USER_PROFILE },
{ query: PROFILE_PAGE, variables: { userName } }
]}>
{/* eslint-disable */}
{(editOtherProfileDetails, { data, loading, error }) => {
/* eslint-enable */
return (
<form className="form" onSubmit={event => this.handleSubmit(event, editOtherProfileDetails)}>
<div className="form_wrap">
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">City</span>
<input type="text" name="locationCity" placeholder="City" value={locationCity} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">State</span>
<input type="text" name="locationState" placeholder="State" value={locationState} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">Country</span>
<input type="text" name="locationCountry" placeholder="Country" value={locationCountry} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">Interests</span>
<input type="text" name="interests" placeholder="Interests (e.g Sports, Wine, Outdoors ect.)" value={interests} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_buttons">
<button type="submit" className="btn">
Save changes</button>
</div>
</div>
</form>
);
}}
</Mutation>
</Fragment>
)
}
}
export default withRouter(EditOtherProfileMutations);
我认为问题在于您的 突变输入字段 与 架构中定义的字段 不同 .
您的架构有:
editOtherProfileDetails(
email: String!,
locationCity: String!,
locationState: String!,
locationCountry: String!,
interests: String!
): User
并且您将突变定义如下:
mutation($locationCountry: String!){ ... }
输入参数必须匹配,所以我认为如果你这样定义你的变异会起作用:
mutation NameOfYourMutation(
$email: String!,
$locationCity: String!,
$locationState: String!,
$locationCountry: String!,
$interests: String!
) { ... }
此外,如您所料,这将慢慢变得难以维护。
我建议看看 input objects.
看
您正在声明采用一个参数的突变,并且在解析器中,它使用电子邮件、locationCity、locationState、locationCountry,对此参数感兴趣但不声明它会导致您应该使用 $locationCity 和其他但它不使用数据文件的问题应该作为参数
作为这个形状
mutation($locationCountry: String!
,$locationCity: String!,
$locationState: String!,
$locationCountry: String!,
$interests: String!){
editOtherProfileDetails(email: $email, locationCity: $locationCity, locationState: $locationState, locationCountry: $locationCountry, interests: $interests){
email
locationCity
locationState
locationCountry
interests
}
提交时告诉我它是否有效
我发现我弄错了。而不是:
const user = await User.findOneAndUpdate({ email },
{ $set: { locationCity: locationCity } },
{ $set: { locationState: locationState } },
{ $set: { locationCountry: locationCountry } },
{ $set: { interests: interests } },
{ new: true }
);
我需要输入:
const user = await User.findOneAndUpdate({ email },
{ $set: { locationCity: locationCity, locationState: locationState, locationCountry: locationCountry, interests: interests } },
{ new: true }
);
我对 React Apollo 和 graphQL 还很陌生。我正在尝试创建一个编辑个人资料表单,将数据添加到用户个人资料中。当我点击提交时没有任何反应并在控制台日志中得到错误:
理想情况下,我希望表单最初呈现用户之前输入的任何数据,以便在提交表单并且他们没有更改所有输入时,他们没有更改的输入也不会在 mongoDB 数据库中被覆盖。
所有和任何建议将不胜感激!谢谢你!
- POST http://localhost:3000/graphql 400(错误请求) [GraphQL 错误]:消息:未定义变量“$email”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$locationCity”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$locationState”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$locationCountry”。,位置:[object Object],[object Object],路径:undefined
- [GraphQL 错误]:消息:未定义变量“$interests”。位置:[object 对象],[object 对象],路径:未定义
- [网络错误]:ServerError:响应不成功:收到状态代码 400
在我的 schema.js 中,我有以下内容:
editOtherProfileDetails(email: String!, locationCity: String!, locationState: String!, locationCountry: String!, interests: String!): User
在我的 resolvers.js 中,我有以下内容:
editOtherProfileDetails: async (root, { email, locationCity, locationState, locationCountry, interests }, { User }) => {
const user = await User.findOneAndUpdate({ email },
{ $set: { locationCity: locationCity } },
{ $set: { locationState: locationState } },
{ $set: { locationCountry: locationCountry } },
{ $set: { interests: interests } },
{ new: true }
);
if (!user) {
throw new Error('User Not Found');
}
return user;
},
在我的 index.js 我有:
export const EDIT_OTHER_PROFILE_DETAILS = gql`
mutation($locationCountry: String!){
editOtherProfileDetails(email: $email, locationCity: $locationCity, locationState: $locationState, locationCountry: $locationCountry, interests: $interests){
email
locationCity
locationState
locationCountry
interests
}
}
`;
在我的 editProfile.js 中,我有以下内容:
import React, { Fragment } from 'react';
import { Mutation } from 'react-apollo';
import {GET_USER_PROFILE, EDIT_OTHER_PROFILE_DETAILS, PROFILE_PAGE } from './../../queries';
import { withRouter } from 'react-router-dom';
import toastr from 'toastr';
const initialState = {
locationCity: '',
locationState: '',
locationCountry: '',
interests: '',
error: ''
}
class EditOtherProfileMutations extends React.Component {
constructor(props) {
super(props);
this.state = {
locationCity: '',
locationState: '',
locationCountry: '',
interests: '',
error: ''
}
}
componentDidMount() {
if (this.props.profile) {
this.setState({
locationCity: this.props.profile.locationCity,
locationState: this.props.profile.locationState,
locationCountry: this.props.profile.locationCountry,
interests: this.props.profile.interests
});
}
toastr.options = {
"closeButton": false,
"debug": false,
"newestOnTop": true,
"progressBar": true,
"positionClass": "toast-bottom-right",
"preventDuplicates": false,
"onclick": null,
"showDuration": "300",
"hideDuration": "1000",
"timeOut": "5000",
"extendedTimeOut": "1000",
"showEasing": "swing",
"hideEasing": "linear",
"showMethod": "fadeIn",
"hideMethod": "fadeOut"
}
}
handleChange(event) {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value.charAt(0).toUpperCase() + value.substr(1).toLowerCase()
});
}
handleSubmit(event, editOtherProfileDetails) {
event.preventDefault();
editOtherProfileDetails().then(async () => {
toastr.success('We have updated your details!', 'Saved!');
}).catch(error => {
this.setState({
error: error.graphQLErrors.map(x => x.message)
})
// console.error("ERR =>", error.graphQLErrors.map(x => x.message));
});
}
render() {
const { locationCity, locationState, locationCountry, interests } = this.state
const userName = this.props.session.getCurrentUser.userName;
this.state;
return (
<Fragment>
<Mutation
mutation={EDIT_OTHER_PROFILE_DETAILS}
variables={{ email: this.props.session.getCurrentUser.email, locationCity, locationState, locationCountry, interests }}
refetchQueries={() => [
{ query: GET_USER_PROFILE },
{ query: PROFILE_PAGE, variables: { userName } }
]}>
{/* eslint-disable */}
{(editOtherProfileDetails, { data, loading, error }) => {
/* eslint-enable */
return (
<form className="form" onSubmit={event => this.handleSubmit(event, editOtherProfileDetails)}>
<div className="form_wrap">
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">City</span>
<input type="text" name="locationCity" placeholder="City" value={locationCity} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">State</span>
<input type="text" name="locationState" placeholder="State" value={locationState} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">Country</span>
<input type="text" name="locationCountry" placeholder="Country" value={locationCountry} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_row">
<div className="form_item">
<div className="form_input">
<span className="edit_profile_span">Interests</span>
<input type="text" name="interests" placeholder="Interests (e.g Sports, Wine, Outdoors ect.)" value={interests} style={{ textTransform: "capitalize"}} onChange={this.handleChange.bind(this)}/>
<span className="bottom_border"></span>
</div>
</div>
</div>
<div className="form_buttons">
<button type="submit" className="btn">
Save changes</button>
</div>
</div>
</form>
);
}}
</Mutation>
</Fragment>
)
}
}
export default withRouter(EditOtherProfileMutations);
我认为问题在于您的 突变输入字段 与 架构中定义的字段 不同 .
您的架构有:
editOtherProfileDetails(
email: String!,
locationCity: String!,
locationState: String!,
locationCountry: String!,
interests: String!
): User
并且您将突变定义如下:
mutation($locationCountry: String!){ ... }
输入参数必须匹配,所以我认为如果你这样定义你的变异会起作用:
mutation NameOfYourMutation(
$email: String!,
$locationCity: String!,
$locationState: String!,
$locationCountry: String!,
$interests: String!
) { ... }
此外,如您所料,这将慢慢变得难以维护。 我建议看看 input objects.
看
您正在声明采用一个参数的突变,并且在解析器中,它使用电子邮件、locationCity、locationState、locationCountry,对此参数感兴趣但不声明它会导致您应该使用 $locationCity 和其他但它不使用数据文件的问题应该作为参数
作为这个形状
mutation($locationCountry: String!
,$locationCity: String!,
$locationState: String!,
$locationCountry: String!,
$interests: String!){
editOtherProfileDetails(email: $email, locationCity: $locationCity, locationState: $locationState, locationCountry: $locationCountry, interests: $interests){
email
locationCity
locationState
locationCountry
interests
}
提交时告诉我它是否有效
我发现我弄错了。而不是:
const user = await User.findOneAndUpdate({ email },
{ $set: { locationCity: locationCity } },
{ $set: { locationState: locationState } },
{ $set: { locationCountry: locationCountry } },
{ $set: { interests: interests } },
{ new: true }
);
我需要输入:
const user = await User.findOneAndUpdate({ email },
{ $set: { locationCity: locationCity, locationState: locationState, locationCountry: locationCountry, interests: interests } },
{ new: true }
);