0
votes

I am creating a project in DialogFlow and NodeJS where I want to call my fulfillments with a webhook. In my NodeJS server, I have multiple routes for different functions/intents. For example, /getWeather calls a weather API to return a response about the weather in a specific city. Or /getMovie calls an API to return information about a movie.

DialogFlow only allows for one webhook API, so my question is, how can I call a generic API "/" where it can handle all the different routes and call the correct route when it needs to?

I can use the inline editor on DialogFlow to call each API with the correct route; however, I want to use a single webhook rather than using the firebase functions to call the correct intents.

I can't seem to find example of this online where multiple routes are handled with a generic route.

Image of my Code Stack

index.js:

const http = require('http');
const app = require('./app');

const port = process.env.PORT || 3000;

const server = http.createServer(app);

server.listen(port);

server.post

app.js

const express = require('express');
const app = express();
const morgan = require('morgan');
const bodyParser = require('body-parser');
const mongoose= require('mongoose');

const issuesRoutes = require('./API/Routes/issues');
const movieRoute = require('./API/Routes/getmovie');
const resolvedtaskroute = require('./API/Routes/resolvedtask');
const newtaskRoute = require('./API/Routes/newtask');

mongoose.connect('link', {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => console.log('MongoDB connected...'))
.catch(err => console.log(err));

app.use(morgan('dev'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use((req, res, next) => {
  res.header('Acces-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', '*');
  if (req.method === 'OPTIONS'){
    res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
    return res.status(200).json({});
  }
  next();
});

//routes to handle requests
app.use('/issues', issuesRoutes);
app.use('/newtask', newtaskRoute);
app.use('/resolvedtask', resolvedtaskroute);
app.use('/getmovie', movieRoute);

//error handling
app.use((req, res, next) => {
  const error = new Error('Not Found');
  error.status = 404;
  next(error);
})

app.use((error, req, res, next) => {
  res.status(error.status || 500);
  res.json({
    error: {
      message: error.message
    }
  })
})

module.exports = app;

Example of one of my routes: getMovie.js

const express = require('express');
const router = express.Router();

const http = require('http');

router.post('/', (req, res, next) => {
    const movieToSearch = req.body.queryResult.parameters.movie;


    const API_KEY = 'XXXXX';
    const reqUrl = `http://www.omdbapi.com/?t=${movieToSearch}&apikey=${API_KEY}`
    http.get(
        reqUrl,
        responseFromAPI => {
            let completeResponse = ''
            responseFromAPI.on('data', chunk => {
                completeResponse += chunk
            })
            responseFromAPI.on('end', () => {
                const movie = JSON.parse(completeResponse)

                let dataToSend = movieToSearch
                dataToSend = `${movie.Title} was released in the year ${movie.Year}. It is directed by ${
                    movie.Director
                    } and stars ${movie.Actors}.
                }`

                return res.json({
                    fulfillmentText: dataToSend,
                    source: 'getmovie'
                })
            })
        },
        error => {
            return res.json({
                fulfillmentText: 'Could not get results at this time',
                source: 'getmovie'
            })
        }
    )
})

module.exports = router;
1
While seeing the filenames are useful, it may help us more if you update your question to show us the code in your index.js, since it sounds like that is what you're asking for help with. See How do I ask a good question? - Prisoner
@jakestar you could try to pass a path parameter or something in the body of the request from the dialogfflow intent to uniquely identify it. Then you could filter it in nodejs before calling the appropriate route. - Y4glory

1 Answers

0
votes

It is very clear that Dialogflow allows one webhook POST url where every call for intents are made. IF you want to use different API services inside then You should define a webhook and inside the webhook just call the functions which are related to intents using intentMAP. On each function call the external API and return the response back to dialogflow. I will describe a bit more about it using dialogflow-fulfillment.

first thing you need is a webhook POST route for handling dialogflow requests and responses and inside it you need to map intents to its specific function as like:

const { WebhookClient } = require("dialogflow-fulfillment");
const movieService= require("your function for movie API");
router.post("/", async (req, res, next) => {
const agent = new WebhookClient({ request: req, response: res });
const movie = new movieService(agent);
let intentMap = new Map();

intentMap.set("Movie Intent", () => {
//make an api call inside this function
return movie.getinfo();
});

if (agent.intent) {
agent.handleRequest(intentMap);
}
});

Now create another file for external API calls which will be like

async getMovie(){
// get all required paramters from dialogflow here and call APIS and return back response using
agent.add("The info about movie is");
}