Updated Backend Integration with Node.js Bot SDK for the Football Chatbot

In the Football Chatbot Series I used the Oracle Integration Cloud (OIC) to implement the Football API backend integration, and Node.js SDK to call the OIC endpoints. This was not the ideal integration implementation but it was the fastest one, so I cut some corners at the time.

Now I will show how to use the Node.js SDK to handle the entire backend Integration, and that will include using the package node-fetch to nest several API calls.

Code

As mentioned before, node-fetch will be the package handling all of the RESP API calls. It is part of the bots-node-sdk and does not require any extra install (the request package, which is now deprecated would require extra steps)

const fetch = require('node-fetch');

The API is from RapidAPI Marketplace – Football API.

We define the API URL’s , for the league, for the results, fixtures , table and scorers. I will use league id as 2790 – which is the English Premier League season 20/21.

const leagueurl =  'https://api-football-v1.p.rapidapi.com/v2/teams/league/2790'
const tableurl =   'https://api-football-v1.p.rapidapi.com/v2/leagueTable/2790'
const scorerurl =  'https://api-football-v1.p.rapidapi.com/v2/topscorers/2790'

Below is a reusable block with the options object that we will be passed to the fetch method.

const options = {
  method: 'GET',  
  headers: {
    'x-rapidapi-key': 'xxxxxx',
    'x-rapidapi-host': 'api-football-v1.p.rapidapi.com',
    useQueryString: true
  }
};

The sequence of requests should be synced as we need to have the team_id before asking for the results/fixtures for that team. For that reason we do not need callbacks/promises. This will be a nested fetch call within another fetch.

Get Results/Fixtures

This code is pretty much the same for getting the results and the fixtures – There is only a difference in the REST URL between results and fixtures.

resultsurl =   'https://api-xxxrapidapi.com/v2/fixtures/team/'team_id'/last/1'
fixturesurl =   'https://api-xxxrapidapi.com/v2/fixtures/team/'team_id'/next/1'

This is pure node.js code, it can run standalone, and once its finalized, it can be merged into the bot-node-sdk custom component.

const getresults = (name) => {
//the variable name should come from the user, but for this test I will pass a value from //the method invocation

fetch(leagueurl,options)
    .then(res => res.json())
    .then(json =>{
        const ft = json.api.teams.find((team) => team.name === name)
       //At this moment the variable ft contains the ID of the Team
       //We need this for the final API Call to get results/fixtures
       
       //this is the url to call the API with the last result for a team_id
       const resultsurl = 'https://apirapidapi.com/v2/fixtures/team/'+ft.team_id+'/last/1'
       fetch(resultsurl,options)
            .then(res => res.json())
            .then(json =>{
                const result = json.api                
                console.log('The last game was '+result.fixtures[0].homeTeam.team_name+ 
                ' VS '+result.fixtures[0].awayTeam.team_name+
                ' for the '+result.fixtures[0].league.name+
                ' . The result was '+result.fixtures[0].score.fulltime+'!') 
                     
    })
    .catch((err) => {
        console.log('Something went wrong in the results api!')
    }); 
         
    })
    .catch((err) => {
        console.log('Something went wrong in the get team id call!')
    }); 
}

This is how the output looks like for both results and fixtures – I am passing “Manchester United” directly to the method. Once I move this to the digital assistant custom component, I will need to fetch the property containing this information (which will come from the Dialog Flow)

Get Scorers

const getscorer = () => {
fetch(scorerurl,options)
    .then(res => res.json())
    .then(json =>{        
        const scorer = json.api 
       // console.log(scorer)               
        console.log('The top 5 scorers for the EPL are:\n 1:    
        '+scorer.topscorers[0].player_name+ ' from ' +scorer.topscorers[0].team_name+
        '\n 2: '+scorer.topscorers[1].player_name+' from ' +scorer.topscorers[1].team_name+
        '\n 3: '+scorer.topscorers[2].player_name+' from ' +scorer.topscorers[2].team_name+
        '\n 4: '+scorer.topscorers[3].player_name+' from ' +scorer.topscorers[3].team_name+
        '\n 5: '+scorer.topscorers[4].player_name+' from ' +scorer.topscorers[4].team_name) 
                     
    })
    .catch((err) => {
        console.log('Something went wrong in the scorer api!')
    }); 

This is how the output looks like.

Get Table

const gettable = () => {
    fetch(tableurl,options)
        .then(res => res.json())
        .then(json =>{        
            const table = json.api 
            //console.log(table.standings)               
            console.log('The top 5 teams in the EPL are:\n 1: '
+table.standings[0][0].teamName+ ' : '+table.standings[0][0].points+ ' pts'+
'\n 2: '+table.standings[0][1].teamName+ ' : '+table.standings[0][1].points+' pts'+
'\n 3: '+table.standings[0][2].teamName+ ' : '+table.standings[0][2].points+' pts'+
'\n 4: '+table.standings[0][3].teamName+ ' : '+table.standings[0][3].points+' pts'+
'\n 5: '+table.standings[0][4].teamName+ ' : '+table.standings[0][4].points+' pts') 
                         
        })
        .catch((err) => {
            console.log('Something went wrong in the table api!')
        }); 
                 
 }

This is how the output looks like.

Merging into Custom Component

Now its time to bring this code into the Custom Component. The entire code will go inside the invoke method, and we need to use the conversation’s methodsreply,transition and keepturn to control how to interact with the Dialog Flow. Below the example for getscorers.js.

'use strict';

const fetch = require("node-fetch");

module.exports = {
  metadata: () => ({
    name: 'gettable',
    properties: {
      team: { required: true, type: 'string' },
    },
    supportedActions: ['sucess', 'failure']
  }),
  invoke: (conversation, done) => {  
    conversation.logger().info("This is my first CC");
    const tableurl =   'https://api-football-v1.p.rapidapi.com/v2/leagueTable/2790'

    const options = {
      method: 'GET',  
      headers: {
        'x-rapidapi-key': 'xxxxxxxx',
        'x-rapidapi-host': 'api-football-v1.p.rapidapi.com',
        useQueryString: true
      }
    };
    
     fetch(tableurl,options)
          .then(res => res.json())
          .then(json =>{        
              const table = json.api                           
              const c = ('The top 5 teams in the EPL are:\n 1: '+table.standings[0][0].teamName+ ' : '+table.standings[0][0].points+ ' pts'+
              '\n 2: '+table.standings[0][1].teamName+ ' : '+table.standings[0][1].points+' pts'+
              '\n 3: '+table.standings[0][2].teamName+ ' : '+table.standings[0][2].points+' pts'+
              '\n 4: '+table.standings[0][3].teamName+ ' : '+table.standings[0][3].points+' pts'+
              '\n 5: '+table.standings[0][4].teamName+ ' : '+table.standings[0][4].points+' pts') 

              conversation.reply(c); 
              conversation.transition('sucess');
              conversation.keepTurn(false);
              done();                           
          })
          .catch((err) => {              
              conversation.logger().info('Something went wrong in the table api!')
          });            
          
      }
  
};

After the code is all done we need to pack the component with:

bots-node-sdk pack

The Football Chatbot post on Backend Integration shows how to bring this package into the Chatbot, and how to modify the Dialog Flow to call these components.

#Dialog Flow Sample on the transition to call the custom component

Table:
    component: System.Output
    properties:
      text: "Let me check that for you!"
    transitions:
      next:
        CCtable
CCtable: 
    component: "gettable"
    properties:        
    transitions:
      return: done

Testing

Because I tested the code separately, this worked flawlessly at first attempt πŸ™‚

Summary

This node.js backend implementation is more realistic as it makes full use of the node-fetch module, and it brings this prototype to a more robust version, with a proper backend integration!

Going forward I will be exploring more of the bots-node-sdk capabilities – https://oracle.github.io/bots-node-sdk/

1 Trackback / Pingback

  1. Build a Football Chatbot with the Oracle Digital Assistant - Part 2 (Backend Integration) – Tech Trantor

Comments are closed.