简体   繁体   中英

React Apollo GraphQL Mutation returns 400 (bad request)

I'm very new to React Apollo and graphQL. I'm trying to create an edit profile form that adds data to the users profile. When I click submit nothing happens and get get errors in the console log:

Ideally I would like the form to initially render with any data that the user has previously entered so that when the form is submitted and they haven't changed all the inputs, the inputs they haven't changed aren't overwritten in the mongoDB database.

All and any advise would be much appreciated! Thank You!

  1. POST http://localhost:3000/graphql 400 (Bad Request) [GraphQL error]: Message: Variable "$email" is not defined., Location: [object Object],[object Object], Path: undefined
  2. [GraphQL error]: Message: Variable "$locationCity" is not defined., Location: [object Object],[object Object], Path: undefined
  3. [GraphQL error]: Message: Variable "$locationState" is not defined., Location: [object Object],[object Object], Path: undefined
  4. [GraphQL error]: Message: Variable "$locationCountry" is not defined., Location: [object Object],[object Object], Path: undefined
  5. [GraphQL error]: Message: Variable "$interests" is not defined., Location: [object Object],[object Object], Path: undefined
  6. [Network error]: ServerError: Response not successful: Received status code 400

In my schema.js I have the following:

editOtherProfileDetails(email: String!, locationCity: String!, locationState: String!, locationCountry: String!, interests: String!): User

In my resolvers.js I have the following:

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;
    },

In my index.js I have:

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
        }
    }
`;

In my editProfile.js I have the following:


    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);

I think the problem is that your mutation input fields are not the same as those defined in your schema .

Your schema has:

editOtherProfileDetails(
 email: String!, 
 locationCity: String!, 
 locationState: String!, 
 locationCountry: String!, 
 interests: String!
): User

And you defined your mutation as follows:

mutation($locationCountry: String!){ ... }

The input params must match, so I think it would work if you define your mutation like this:

mutation NameOfYourMutation(
 $email: String!, 
 $locationCity: String!, 
 $locationState: String!, 
 $locationCountry: String!, 
 $interests: String!
) { ... }

Also, as you might anticipate, this will slowly become hard to maintain. I recommend having a look at input objects .

look you are declaring mutation that take one argument and in resolver, it using email, locationCity, locationState, locationCountry, interests this args but not declare it will cause the problem you should be you are used the $locationCity and other but it doesn't datafiles should be take as argument
as this shape

      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

}

tell me in commit if it works or not

I figured out that I had made a mistake. Instead of:

const user = await User.findOneAndUpdate({ email }, 
    { $set: { locationCity: locationCity } }, 
    { $set: { locationState: locationState } }, 
    { $set: { locationCountry: locationCountry } }, 
    { $set: { interests: interests } }, 
    { new: true }
  );

I needed to put:

const user = await User.findOneAndUpdate({ email }, 
    { $set: { locationCity: locationCity, locationState: locationState, locationCountry: locationCountry, interests: interests } }, 
    { new: true }
  );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM