node.jsexpressdialogflow-esdialogflow-es-fulfillment

DialogFlow v2 Error: Resource name '' does not match 'projects/*/locations/*/agent/environments/*/users/*/sessions/*'


I'm trying to implement a custom chat window for a DialogFlow chatbot. AFAIK, I need to create a server to handle requests from the chat window, forward them to DialogFlow for a response, and then return that response to the chat window. I followed the sample from the DialogFlow Node.js client SDK (step 6: "Try an example") and ended up with this:

require('dotenv').config()
const dialogflow = require('dialogflow');
const express = require('express');    

const app = express();
const PORT = process.env.PORT || 3000;    

app.use(express.json());    

const sessionClient = new dialogflow.SessionsClient({
  credentials: {
    client_email: process.env.CLIENT_EMAIL,
    private_key: process.env.PRIVATE_KEY
  }
});    

async function getResponse(req, res) {
  // A unique identifier for the given session
  console.log("body", req.body);
  const sessionId = req.body.session.split('/').pop();    

  // Create a new session
  console.log("session", sessionId)

  const sessionPath = sessionClient.sessionPath(process.env.PROJECT_ID, sessionId);    

  // The text query request.
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        // The query to send to the dialogflow agent
        text: req.body.queryResult.queryText,
        // The language used by the client (en-US)
        languageCode: 'en-US',
      }
    }
  };    

  console.log("send request", request)
  // Send request and log result
  const responses = await sessionClient.detectIntent(req);
  const result = responses[0].queryResult;
  res.json(result);
}    

app.post('/', getResponse);
app.get('/', (req, res) => res.send('Use POST'));
app.listen(PORT, () => {
  console.log('Server is running on PORT:',PORT);
});

Although the original sample worked, sending a POST request to my server using Postman gives me this error:

(node:724) UnhandledPromiseRejectionWarning: Error: 3 INVALID_ARGUMENT: Resource name '' does not match 'projects/*/locations/*/agent/environments/*/users/*/sessions/*'.
    at Object.callErrorFromStatus (C:\Users\rudyt\Documents\Github\metbot-fulfillment\node_modules\@grpc\grpc-js\build\src\call.js:30:26)
    at Http2CallStream.call.on (C:\Users\rudyt\Documents\Github\metbot-fulfillment\node_modules\@grpc\grpc-js\build\src\client.js:96:33)
    at Http2CallStream.emit (events.js:194:15)
    at process.nextTick (C:\Users\rudyt\Documents\Github\metbot-fulfillment\node_modules\@grpc\grpc-js\build\src\call-stream.js:75:22)
    at process._tickCallback (internal/process/next_tick.js:61:11)
(node:724) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:724) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I'm not sure where this error is coming from, whether there's an issue with how I formatted the request in my getResponse function or if somehow it's related to Postman? The query I'm making (on the Postman side) is a POST to http://localhost:3000 with the Content-Type header set to application/json and the request body set as raw JSON (I pasted in this sample Webhook request). I'm leaning towards the issue being with the request to DialogFlow but I included the Postman info just in case.


Solution

  • I think the problem is that you're not sending what you think you're sending to detectIntent().

    Assuming this code is meant to run on a server somewhere, take the request from the JavaScript client, and then create a request to Dialogflow - you're not actually doing that.

    Although you are creating the request (in a constant named request) and logging it

      // The text query request.
      const request = {
        session: sessionPath,
        queryInput: {
          text: {
            // The query to send to the dialogflow agent
            text: req.body.queryResult.queryText,
            // The language used by the client (en-US)
            languageCode: 'en-US',
          }
        }
      };    
    
      console.log("send request", request)
    

    when you go to send this to Dialogflow you're not sending the request object, but rather the req object, which is what came from the client:

    const responses = await sessionClient.detectIntent(req);
    

    You should never pass something from a client without sanitizing it in your server first.

    I suspect if you change it to something like this, it should work:

    const responses = await sessionClient.detectIntent(request);