Search code examples
reactjsgraphqlclientapollo-clientreact-fullstack

problems on request POST mutation on GraphQL and REACT


i receive 400 bad request when i try to add a task on my website! need help =( i see people also returning all the page return() in every function, should i do the same? or i can leave the return at the end of the code

import './App.css';
import Task from './Task';
import React from 'react';
import TaskForm from './TaskForm';
import { useEffect, useState } from "react";
import {useQuery,gql,useMutation} from '@apollo/client'

const GET_TASKS = gql`
  query GetTasks {
    tasks {
      name
      done
    }
  }
`;

const ADD_TASK = gql`
mutation newTask($input: taskInput!) {
  newTask(input: $input) {
    name
  }
}
`;

function App() {
  const taskss  = useQuery(GET_TASKS);
  console.log(taskss)
  
  const [tasks, setTasks] = useState(() => {
    const storedTasks = JSON.parse(localStorage.getItem('tasks'));
    return storedTasks ?? [];
    //return storedTasks !== null ? storedTasks : [];
  });

  useEffect(() => {
    localStorage.setItem('tasks', JSON.stringify(tasks));
  }, [tasks]);


  const [addTaskMutation, { data, loading, error }] = useMutation(ADD_TASK, {
    onCompleted: (data) => {
      setTasks(prevTasks => [...prevTasks, data.addTask]);
    }
  });

  function AddTask(name) {
    addTaskMutation({ variables: {input: name } });
  }


  function removeTask(indexToRemove) {
}
  
  function updateTaskDone(taskIndex, newDone) {
  }
  
  function getMessage() {
    const percentage = numberTotal === 0 ? 0 : (numberComplete / numberTotal) * 100;
    if (percentage === 0) {
      return 'no tasks complete 😾';
    }
    if (percentage === 100) {
      return 'nice job! 😻';
    }
    return 'keep it up! 😼';
  }

  function renameTasks(index, newName) {
  }

  const numberComplete = tasks.filter(t => t.done).length;
  const numberTotal = tasks.length;
    
  return (
    <main>
      <h1>{numberComplete}/{numberTotal} Complete</h1>
      <h2>{getMessage()}</h2>
      <TaskForm onAdd={AddTask} />
      {taskss.data && taskss.data.tasks && taskss.data.tasks.map((task, index) => (
        <Task
          {...task}
          key={index}
          onRename={newName => renameTasks(index, newName)}
          onTrash={() => removeTask(index)}
          onToggle={done => updateTaskDone(index, done)}
        />
      ))}
    </main>
  );

}

export default App;

i am showing you also the Schema

const { makeExecutableSchema } = require('@graphql-tools/schema');
const { resolvers } = require('./resolvers');

const typeDefs = `#graphql

    type Query {
        tasks: [Task!]!
    } 

    type Mutation{
        newTask( input: taskInput!): Task
        updatedTask( id: ID!): Boolean
        deletedTask( id: ID!): Boolean
        updatedTitle( id: ID! input: titleInput!): Boolean
    }

    input titleInput{
        name: String!
    }

    input taskInput{
        name: String!
    }

    type Task {
        name: String!
        done: Boolean!
        id: ID!
    }
`
const schema = makeExecutableSchema({ typeDefs, resolvers });
module.exports = {schema}

and this is the resolver, everything seems to work on apollo


const { client } = require('./controllers/tasks');

const resolvers = {
  Query: {
    tasks: async (parent, args, context, info) => {
      const result = await client.search({
        index: 'tasks',
        body: {
          query: {
            match_all: {}
          }
        }
      })
      const tasks = result.hits.hits.map((hit) => {
        const task = hit._source;
        task.id = hit._id; 
        return task;
      });
  
      return tasks;
    },
  },
  Mutation: {
    
    updatedTitle: async (parent, args, context, info) => {
      const { id ,input } = args;
      const newName = input.name
      const response = await client.update({
        index: 'tasks',
        id: id,
        body: {
          doc: {
            name: newName
          }
        }
      });
    },

    deletedTask: async (parent, args, context, info) => {
      const id = args.id
      await client.delete({
        index: 'tasks',
        id: id,
      });
    },


    updatedTask: async (parent, args, context, info) => {
      const id = args.id
      const task = await client.get({
        index: 'tasks',
        id: id
      });
      await client.update({
          index: 'tasks',
          id: id,
          body: {
            doc: {
              done: !task._source.done
            }
          }
        });
    },

    newTask: async (parent, {input}, context, info) => {  
      const newTask = {
        name: input.name,
        done: false
      };

      const result = await client.index({             
        index: 'tasks',
        body: newTask
      });

      const { _id } = result;                               
      newTask._id = _id;

      return newTask;
    }
  }
};

module.exports = { resolvers };


Solution

  • Look at your mutation in the client:

    const ADD_TASK = gql`
    mutation AddTask($name: String!) {
      addTask(name: $name, done: false) {
        name
        done
      }
    }
    `;
    

    Now compare that to the mutations you have defined on the server:

    type Mutation{
      newTask( input: taskInput!): Task
      updatedTask( id: ID!): Boolean
      deletedTask( id: ID!): Boolean
      updatedTitle( id: ID! input: titleInput!): Boolean
    }
    
    1. There is no addTask mutation
    2. The newTask mutation takes a single parameter input of type taskInput - you are sending two parameters to addTask, (name: $name, done: false) - even if you fixed the name you'd still have a mismatch with the parameters