Skip to Content
Technical Articles
Author's profile photo Yohei Fukuhara

The simplest connection between Node.js app and SAP Conversational AI

Hi All,

I am writing this blog to describe the simplest way to use SAP Conversational AI with Node.js application on SAP Cloud Platform Cloud Foundry.



Local PC

  • Ubuntu18.04.01 LTS on VMWare Workstation
  • cf CLI 6.43.0
  • node.js 11.10.1
  • npm 6.7.0

Cloud Foundry

  • Nodejs Buildpack version 1.6.40
  • CF Trial (Europe – Frankfurt)


  • space is created on Cloud Foundry environment
  • cf CLI is installed on Local PC(see the official page for the installation)
  • Node.js is installed on Local PC(see another article)


1. Node.js development

1.1. Setup Node.js on Local PC

Create a directory.

mkdir chat_test
cd chat_test

1.2. Setup npm

Initialize npm.  After  “npm init” command, I answered like this.

$ npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (chat_test) chat-test
version: (1.0.0) 
entry point: (index.js) app.js
test command: 
git repository: 
license: (ISC) 
About to write to /home/i348221/Apps/node/chat_test/package.json:

  "name": "chat-test",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "author": "",
  "license": "ISC"

Is this OK? (yes) yes

1.3. Install express and body-parser

Install express and body-parser via npm.

npm install --save express body-parser

1.4.  Change package.json

Change package.json file for startup registration on SAP Cloud Platform.  I changed “scripts” -> “start” part.

  "name": "chat-test",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.4"

Now the directory is like this.

$ ls -al
total 32
drwxr-xr-x  3 i348221 i348221  4096 Mar  7 19:24 .
drwxr-xr-x  6 i348221 i348221  4096 Mar  7 18:00 ..
drwxr-xr-x 51 i348221 i348221  4096 Mar  7 19:24 node_modules
-rw-r--r--  1 i348221 i348221   283 Mar  7 19:24 package.json
-rw-r--r--  1 i348221 i348221 13929 Mar  7 19:24 package-lock.json

1.5. Main program “app.js”

Create app.js in the same directory.

tourch app.js

Contents of “app.js”.

I prepared for “get” and “post” method, though I don’t use “get” method.  It is just test purpose.

// Import modules
const express = require('express')
const bodyParser = require('body-parser');

const app = express()

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

// Get method
app.get('/', (req, res) => res.send('Hello World! for GET'))

// Post method'/', function(req, res) {
  console.log('Start [POST] method to / ');

  console.log(`Request from user: ${req.body.conversation.memory['user']}`)

// Response Body
    replies: [
      type: 'text',
      content: `Hello ${req.body.conversation.memory['user']}`
    conversation: {
      memory: {
        'result': 'OK',

// Listen 
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

1.6. Test Node.js application

For verifying the “app.js” on local PC, run “app.js”.

$ node app.js
Example app listening on port 3000!

I used POSTMAN for the test.

The result of “get” method.

The one of “post” method.  Don’t forget about request

Headers and Body.

The “post” Request Body. Most of data is unnecessary.

    "action_id": "5149f96e-b2c5-4e30-96ec-c587ae978d52",
    "conversation": {
        "id": "test-1530310812548",
        "memory": { 
        	"user": "Homer"
        "language": "en",
        "skill": "foo",
        "skill_occurences": 2
    "nlp": {
        "act": "assert",
        "language": "en",
        "processing_language": "en",
        "sentiment": "neutral",
        "source": "This is a sample message.",
        "status": 200,
        "timestamp": "2018-06-29T22:00:50.591367+00:00",
        "type": null,
        "uuid": "c1bc4e40-ca14-4ce2-bc18-700433b001d9",
        "version": "2.12.0"

After sending a request, I can see logs via terminal.

I exported POSTMAN.

2. Deploy Node.js app to SAP CP

2.1. Create manifest.yaml

For deployment to SAP Cloud Foundry, manifest.yaml is necessary.

touch manifest.yaml

The file content is like this.

- name: chat-test
  random-route: true
  memory: 128M

2.2. Deploy the app to SAP CP Cloud Foundry

Login SAP CP Cloud Foundry via CF cli.

cf login

Now deploy the app!  Application name is from “manifest.yaml”.

cf push

3. SAP Conversational AI

3.1. Create chatbot

I created a simple chatbot, which doesn’t have any intents and skills.

I used “fallback” skill for the connection with Node.js.

This is the action of “fallback” skill and just send POST request without authentication.  Don’t forget about Header “Content-Type” is “application/json”.

3.2. Check the connection

Now check the connection.


I can see logs via CF cli.

cf logs chat-test --recent


Here is the logs.

2019-03-07T23:47:57.60-0800 [APP/PROC/WEB/0] OUT Start [POST] method to / 
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT { nlp: 
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT    { uuid: '1d8ca70e-f889-4ce4-a643-20b330ed7522',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      intents: [],
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      entities: {},
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      language: 'en',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      processing_language: 'en',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      version: '1902.2.0',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      timestamp: '2019-03-08T07:47:57.074401+00:00',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      status: 200,
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      source: 'HI',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      act: 'assert',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      type: 'desc:desc',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      sentiment: 'vpositive' },
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT   action_id: '78538f72-0fe9-4d64-89a9-631d76862bc1',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT   conversation: 
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT    { id: 'test-1552031274266',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      conversation_id: 'test-1552031274266',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      warning: 'The conversation_id field will be depreciated on January 1st 2018! Switch to using the id field instead',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      language: 'en',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      memory: { user: 'Test' },
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      skill_stack: [],
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      skill: 'fallback',
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      skill_occurences: 1,
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT      participant_data: {} } }
   2019-03-07T23:47:57.61-0800 [APP/PROC/WEB/0] OUT Request from user: Test
   2019-03-07T23:47:57.61-0800 [RTR/3] OUT - [2019-03-08T07:47:57.558+0000] "POST / HTTP/1.1" 200 647 94 "-" "axios/0.18.0" "-" "" x_forwarded_for:"-" x_forwarded_proto:"https" vcap_request_id:"6f2d89a0-5bdf-45c1-6250-9a7358b5f059" response_time:0.056351563 app_id:"610382d3-8749-44eb-b29e-d40787a15fbb" app_index:"0" x_correlationid:"-" x_b3_traceid:"acc413c482b12ac1" x_b3_spanid:"acc413c482b12ac1" x_b3_parentspanid:"-"
   2019-03-07T23:47:57.61-0800 [RTR/3] OUT 

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo maria mallari
      maria mallari

      Thanks for this great tutorial. I learned a lot. I just have a question. How will this work out if we are to add an app router for the node js?

      Author's profile photo Yohei Fukuhara
      Yohei Fukuhara
      Blog Post Author

      I have no idea with App Router.  Why do you like to add App Router?

      Author's profile photo maria mallari
      maria mallari

      It's to secure the endpoint with authentication once deployed to the cloud. I can't seem to make the post call work when I added it.

      Author's profile photo Yohei Fukuhara
      Yohei Fukuhara
      Blog Post Author

      How about checking OAuth token on Node.js.
      Though I don't know how to do with Node.js, I achieved the validation on Java with SAP Cloud SDK.