How to call one node.js script from multiple node.js scripts based on the request body variable in Target Endpoints?

brinda
New Member

Hi,

I have 5 node.js scripts in my proxy and I need to write a condition which checks the formName variable from request body and calls the script accordingly. I couldn't find any document regarding this issue. What I am trying to do clearly doesn't seem to work.
Does any have any ideas on how to do that?

I want to write the condition in the TargetEndpoints Policy and not Node.js script.

This is what I am doing which clearly doesn't work.

 <ScriptTarget>
        <if request.body.formName = "RequestAccessToExistingAPI">
            <ResourceURL>node://footprints-soap-relay.js</ResourceURL>
        </if>
        <if request.body.formName = "RequestAccessToExistingEventNotification">
            <ResourceURL>node://RequestAccessToExistingEventNotification.js</ResourceURL>
        </if>
    </ScriptTarget>
Solved Solved
0 7 1,155
1 ACCEPTED SOLUTION

Yes, I understand.

There is no possibility to insert a condition or IF statement within the ScriptTarget element. That's not valid.

ONE WAY to do what you want is to insert the condition in the RouteRule, which is part of the API Proxy endpoint. Define two targets, and then route to the one you want.

target1.xml:

<TargetEndpoint name='target1'> 
  <ScriptTarget> <ResourceURL>node://footprints-soap-relay.js</ResourceURL></ScriptTarget>
</TargetEndpoint>

target2.xml:

<TargetEndpoint name='target2'> 
  <ScriptTarget> <ResourceURL>node://RequestAccessToExistingEventNotification.js</ResourceURL></ScriptTarget>
</TargetEndpoint>

then, in the proxy endpoint .xml file:

<ProxyEndpoint> 
  ...
  <RouteRule name='rule1'>
    <Condition>request.body.formName = "RequestAccessToExistingAPI"</Condition>
    <TargetEndpoint>target1</TargetEndpoint>
  </RouteRule>
  <RouteRule name='rule2'>
    <Condition>request.body.formName = "RequestAccessToExistingEventNotification"</Condition>
    <TargetEndpoint>target2</TargetEndpoint>
  </RouteRule>
  ...

A SECOND WAY to do what you want is to insert those conditions in the nodejs itself. Supposing you are using the node http module to handle inbound requests, your function looks like this:

function handleInboundRequest(req, resp) {
    ....
}

You can examine grab the request data and examine it, then act accordingly. Like this:

function handleInboundRequest (req, resp) {
    if (req.method == 'POST') {
        var payload = '';

        req.on('data', function (data) {
            payload += data;
        });

        req.on('end', function () {
            // payload now contains the POST payload
        });
    }
}

But it's much much easier to do this with a module that helps you out, like expressjs. Whichever way you do it, the point is you can insert the conditionals in the nodejs code itself, rather than in the RouteRules.

View solution in original post

7 REPLIES 7

Yes, I understand.

There is no possibility to insert a condition or IF statement within the ScriptTarget element. That's not valid.

ONE WAY to do what you want is to insert the condition in the RouteRule, which is part of the API Proxy endpoint. Define two targets, and then route to the one you want.

target1.xml:

<TargetEndpoint name='target1'> 
  <ScriptTarget> <ResourceURL>node://footprints-soap-relay.js</ResourceURL></ScriptTarget>
</TargetEndpoint>

target2.xml:

<TargetEndpoint name='target2'> 
  <ScriptTarget> <ResourceURL>node://RequestAccessToExistingEventNotification.js</ResourceURL></ScriptTarget>
</TargetEndpoint>

then, in the proxy endpoint .xml file:

<ProxyEndpoint> 
  ...
  <RouteRule name='rule1'>
    <Condition>request.body.formName = "RequestAccessToExistingAPI"</Condition>
    <TargetEndpoint>target1</TargetEndpoint>
  </RouteRule>
  <RouteRule name='rule2'>
    <Condition>request.body.formName = "RequestAccessToExistingEventNotification"</Condition>
    <TargetEndpoint>target2</TargetEndpoint>
  </RouteRule>
  ...

A SECOND WAY to do what you want is to insert those conditions in the nodejs itself. Supposing you are using the node http module to handle inbound requests, your function looks like this:

function handleInboundRequest(req, resp) {
    ....
}

You can examine grab the request data and examine it, then act accordingly. Like this:

function handleInboundRequest (req, resp) {
    if (req.method == 'POST') {
        var payload = '';

        req.on('data', function (data) {
            payload += data;
        });

        req.on('end', function () {
            // payload now contains the POST payload
        });
    }
}

But it's much much easier to do this with a module that helps you out, like expressjs. Whichever way you do it, the point is you can insert the conditionals in the nodejs code itself, rather than in the RouteRules.

Hi @Dino

Thank you again!!

I will try the first one out and let you know.

For your second option, I am not quiet clear how to check the formName(request text) value?

This is the text that I receive from form and I want to check whether the formName is XXX, if yes, then it should proceed further.

formName=RequestAccessToExistingAPI&existingApi_netID=g&text=XXXX&existingApi_appName=g&existingApi_Desc=g&existingApi_apikeycheck=No&existingApi_appName=&submit=Submit

I have 5 node.js scripts for 5 forms. And depending on the form name the node.js script should be executed.

If you use nodejs with an http server...

var http = require('http');
   ...
var svr = http.createServer(handleInboundRequest);
svr.listen(process.env.PORT || 9000, function() {
    console.log('Node HTTP server is listening');
});

..then it is quite laborious to extract the form parameters from the inbound request. See here.

A better option is to use a module like express that allows you easier access to form parameters.

var app = require('express')();
var bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(bodyParser.json());

app.post(/^\/.*/, function (req, res) {
    if (req.body.formName == "RequestAccessToExistingAPI") {
     ...
    }
    else {
     ...
    }
});

See here.

In my experience, this works with express v4.13.3 , within trireme (inside Apigee Edge).

Hi @Dino

I am getting this error.

{"fault":{"faultstring":"Script node executed prematurely: TypeError: Cannot find function use in object \nfunction createApplication() {...}.\nTypeError: Cannot find function use in object \nfunction createApplication() {...}.\n    at \/organization\/environment\/api\/footprints-soap-relay.js:17\n    at module.js:456\n    at module.js:474\n    at module.js:356\n    at module.js:312\n    at module.js:497\n    at startup (trireme.js:142)\n    at trireme.js:923\n","detail":{"errorcode":"scripts.node.runtime.ScriptExitedError"}}}
app.use(bodyParser.urlencoded
({
    extended: true
}));


app.use(bodyParser.json());


app.post(/^\/.*/, function ( req , res)
{
    formName = req.body.formName;
});


if ( formName == "RequestAccessToExistingAPI" )
{
    var svr = http.createServer(handleInboundRequest);
    svr.listen(process.env.PORT || 9000, function() 
    {
        console.log('Node HTTP server is listening');
    });
}

It cannot find function app.use or app.all or app.post? I installed express manually too but I still see this error

var app = express(); or var app = require('express')();

Even this doesnt work. It throws this error:

*** Script footprints-soap-relay.js exited with status code 0

Hi Brinda

I think the code you posted is incomplete. It's also confused.

If you want to refer to form parameters with "req.body.formName" , then you need to write an express app. That means you need to require express. Here's a tutorial .

Your code should look something like this:

var express = require('express');
var app = express();
var bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post(/^\/.*/, function ( req , res)
{
    if (req.body.formName == 'RequestAccessToExistingAPI') {
      // handle the request appropriately
    }
    else ...

});

var portIgnored = 5950;
app.listen(portIgnored,function(){ console.log("Started listening");});

Hi @Dino

I also tried the first option of RouteRule but that too failed. I am getting this error:

{"fault":{"faultstring":"Unable to route the message to a Target Endpoint","detail":{"errorcode":"messaging.runtime.RouteFailed"}}}

I think its not able to compare formName.

Hi @Dino

The first solution worked. The only mistake I was making was setting the form method as POST. The method should be GET for FORM.

Then I got the request as querystring. So I used ExtractVariable and set FormName there and set the rule.

It worked.