node.jsexpresselasticsearchgraphqlexpress-graphql

how to interact and fetch data from elasticsearch to graphql APOLLO 4


so here's my code, i'm really stuck my friends, i have no idea how to send data from my database to graphql, even when i try to do a POST request i receive NULL! here's my code divided in 5 files.

server.js, the connection seems to work correctly, i can access to my database, and apollo

const express = require('express')
const app = express()
const tasks = require('./routes/tasks')
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone')
const { ApolloServerPluginDrainHttpServer } = require('@apollo/server/plugin/drainHttpServer');
const { schema } = require('./schema.js');
const { resolvers } = require('./resolvers.js');
const http = require('http');
const cors = require('cors');
const { json } = require('body-parser');
const { expressMiddleware } = require('@apollo/server/express4');

app.use(express.json())
app.use(express.urlencoded({ extended: false }))

const httpServer = http.createServer(app);
const server = new ApolloServer({
  schema,
  resolvers,
  plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});

const startServer = async () => {
  await startStandaloneServer(server, {
    listen: { port: 5555 },
  });
  console.log(`Server ready at: localhost:5555`);
  console.log('Query at: https://studio.apollographql.com/dev');

  app.use(
    '/graphql',
    cors(),
    json(),
    expressMiddleware(server, {
      context: async ({ req }) => ({ token: req.headers.token }),
    })
  );

  app.listen(5551, () => {
    console.log('port: 5551');
  });
};

startServer();

tasks.js (routes)

const express = require('express')
const router = express.Router()
const {getTasks,addTasks,changeTasks,deleteTasks,updateTaskDone} = require('../controllers/tasks')
router.use(express.json())
router.use(express.urlencoded({extended:false}))

router.get('/', getTasks);
router.post('/', addTasks);
router.put('/done/:id', updateTaskDone);
router.delete('/delete/:id', deleteTasks);
router.put('/rename/:id',changeTasks)

module.exports = router;

tasks.js (controllers) should i create the query for graph here??

const {Client} = require('@elastic/elasticsearch')

const client = new Client({
  node: 'https://localhost:9200',
  auth: {
      username:"elastic",
      password:"rphcDrBrEm_i1D7_A+hS",
  },
  tls: {
      rejectUnauthorized: false
    }
})

async function run(){
  console.log("connected to elastic!");
  
}

run().catch(errore =>{
  console.log("errore");
})

let tasks = []

const getTasks =  async (req, res) => {
  const result = await client.search({
    index: 'tasks',
    body:{
      query:{
        match_all: {}
      }
    }
  })
  res.status(200).json({success:true, tasks:tasks})
  }

  
  const addTasks = async (req, res) => {
    const { name } = req.body;
    const newTask = { name: name, done: false };
    const result = await client.index({
      index: 'tasks',
      body: newTask
    });
    const { _id } = result;
    newTask._id = _id;
    console.log("Task creata con successo, ID:",_id)
    tasks.push(newTask);
    res.status(201).json(newTask);
  }
  

  const updateTaskDone = async (req, res) => {
    const { id } = req.params;
    const taskIndex = tasks.findIndex(task => task._id === id);
    const tasksToUpdate = [...tasks];
      
    if (tasksToUpdate[taskIndex].done) {
      await client.update({
        index: 'tasks',
        id: id,
        body: {
          doc: {
            done: false
          }
        }
      });
      tasksToUpdate[taskIndex].done = false;
      }else {
      await client.update({
        index: 'tasks',
        id: id,
        body: {
          doc: {
            done: true
          }
        }
      });
      tasksToUpdate[taskIndex].done = true;
    }
    console.log("Task aggiornata con successo, ID:",id)
    tasks = tasksToUpdate;
    res.status(200).json({ success: true, task: tasks });
};
  

const changeTasks = async (req, res) => {
  const { id } = req.params;
  const tasksToUpdate = [...tasks];
  const { newName } = req.body;
  const taskIndex = tasks.findIndex(task => task._id === id);
  await client.update({
    index: 'tasks',
    id: id,
    body: {
      doc: {
        name: newName
      }
    }
  });
  tasksToUpdate[taskIndex].name = newName;
  tasks = tasksToUpdate;
  res.status(200).json({ success: true, task: tasks });
};



const deleteTasks = async (req, res) => {
  const { id } = req.params;
  const taskIndex = tasks.findIndex(task => task._id === id);
  const tasksToUpdate = [...tasks];
  const taskToDelete = tasks.splice(tasksToUpdate[taskIndex], 1);
  await client.delete({
    index: 'tasks',
    id: id,
  });
  const updatedTasks = [...tasks];
  tasks = updatedTasks;
  res.status(200).json({ success: true, tasks: updatedTasks  });
  console.log("Task eliminata con successo, ID:",id)
};


module.exports = {getTasks,addTasks,changeTasks,deleteTasks,updateTaskDone,client}

schema.js i tried to create just 1 mutation, no more because i am stuck already

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

const typeDefs = `#graphql

    type Query {
        tasks: [Task!]!
    } 

    type Mutation{
        newTask( input: taskInput): Task
    }

    input taskInput{
        name: String!,
        done: Boolean!,
    }

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

resolvers.js

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

const resolvers = {
  Query: {
    tasks: async (parent, args, context, info) => {
      const { body } = await client.search({
        index: 'tasks',
        body: {
          query: {
            match_all: {}
          }
        }
      });

      const tasks = body.hits.hits.map(hit => hit._source);

      return tasks;
    }
  },

  Mutation: {
    newTask: async (parent, args, context, info) => {
      const { input } = args;
      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 };

and when i try to send a POST request trough postman

{
  "query": "mutation newTask($input: taskInput) { newTask(input: $input) { _id name done } }",
  "variables": {
    "input": {
      "done": false,
      "name": "lol123123123"
    }
  }
}

this is what i receive back

{
    "data": {
        "newTask": null
    }
}

Solution

  • I see you have this line:

    const schema = makeExecutableSchema({ typeDefs });
    

    I think it should be:

    const schema = makeExecutableSchema({ typeDefs, resolvers });
    

    (Being sure to import the resolvers from the relevant file.)

    The "executable" part of an executable schema is the resolvers - without them, the system does not know what to do when a field is to be executed and so it just does the default behaviour of returning that named property of the parent object (or rootValue at the root). This is why you're seeing a null.