How do you iterate Collection from "request.queryparams.names" in JS ?

Not applicable

I am creating a JavaScript policy for an API and I am attempting to iterate the query parameter names to see which ones have been sent.

I used the context variable "request.queryparams.names" which I saw in the documentation as returning a variable of type "Collection"

var queryParamNames = context.getVariable("request.queryparams.names");

I could not iterate this variable in a loop nor could I invoke a "hasOwnProperty()" method on it. It kind of does not make sense to me as a Collection in JavaScript either is an array or a structured object and this seems to be neither.

When I trace my api request and see the variable in listed it shows up like [value1, value2] which looks like an array, but if I invoke

Object.prototype.toString.call(queryParamNames)

The type comes out to the JavaObject.

So firstly, why is that ?

Secondly, is this what is meant by a Collection because the docs don't say you get back a JavaObject ?

Thirdly, how do I iterate the query parameter names of this JavaObject ?

Thanks.

Solved Solved
3 14 9,724
1 ACCEPTED SOLUTION

Hi @Georges Haddad

Sorry you're having trouble using the request.queryparams.names context variable from within JS.

I cannot solve that immediate problem for you, but I can suggest something that might be useful as a workaround. I use URI.js often within my JS for parsing query params and so on.

To use it, you'd need to include the source of URI.js into your resources/jsc directory, and you'd need to specify it like this in the JS callout policy configuration:

<Javascript name='Javascript-ParseQparams' timeLimit='200' >
  <IncludeURL>jsc://URI.js</IncludeURL> 
  <ResourceURL>jsc://parseQparams.js</ResourceURL>
</Javascript>

And then your JS code would look something like this:

var uri = URI(context.getVariable('request.uri'));

// get data map:
var search = uri.search(true);

// suppose the inbound API request looks like:
// http://host/basepath/suffix?param1=value1a&param1=value1b&param2=value2
//
// then, the search object would look like this: 
// {
//   "param1": [
//     "value1a",
//     "value1b"
//   ],
//   "param2": "value2"
// }

View solution in original post

14 REPLIES 14

Dear @Georges Haddad , Welcome to Apigee Community. We see the same results. Let us look into it.

@krupa , Any idea what is the root cause ?

Hi @Georges Haddad

Sorry you're having trouble using the request.queryparams.names context variable from within JS.

I cannot solve that immediate problem for you, but I can suggest something that might be useful as a workaround. I use URI.js often within my JS for parsing query params and so on.

To use it, you'd need to include the source of URI.js into your resources/jsc directory, and you'd need to specify it like this in the JS callout policy configuration:

<Javascript name='Javascript-ParseQparams' timeLimit='200' >
  <IncludeURL>jsc://URI.js</IncludeURL> 
  <ResourceURL>jsc://parseQparams.js</ResourceURL>
</Javascript>

And then your JS code would look something like this:

var uri = URI(context.getVariable('request.uri'));

// get data map:
var search = uri.search(true);

// suppose the inbound API request looks like:
// http://host/basepath/suffix?param1=value1a&param1=value1b&param2=value2
//
// then, the search object would look like this: 
// {
//   "param1": [
//     "value1a",
//     "value1b"
//   ],
//   "param2": "value2"
// }

Thanks @Dino, that's a good way to go around the issue. I actually did the same workaround but manually parsing the querystring. This URI.js package looks like it can do the job better.

Not applicable

Hi @Georges Haddad

Hope this help!

//Convert Collection to string

var queryFieldsCollection = context.getVariable('request.queryparams.names') + '';

//Remove square brackets

queryFieldsCollection = queryFieldsCollection.substr(1, queryFieldsCollection.length - 2);

//Split string into an array

var queryFieldsArray = queryFieldsCollection.split(", ");

Once you have array, you iterate and get the array elements

--Regards,

Nagesh

Hi @nagesh thanks for that answer, though it is the same kind of workaround as getting the query fields form context.getVariable("request.querystring"); Either way still have to parse the feilds, at least with @Dino's answer you'd write less code and handle the parsing of the query params to the URL.js library.

Not applicable

I'm assuming that apigee has some Java layer underneath it and that's probably the reason why this function would return a JavaObject in javascript. It's still accessible in JS but not as a standard JS collection. I assume we would have to know what the methods are of the netscape (I believe?) wrapper on Java objects. @Dino so far has the best solution, but it still does not answer my 3 questions listed above.

Yes, that is correct. The Javascript you write runs within Rhino, which is hosted in a Java VM. The thing you are getting is a Java object, an instance of java.util.Set.

> it it still does not answer my 3 questions listed above.

True enough! I'll address your questions but can't promise you satisfaction.

> why is that?

I can't answer that, I don't know. It just is. It was designed this way.

> is this what is meant by a Collection

I suppose so.

> how do I iterate the query params?

try this:

var queryParamNames = context.getVariable("request.queryparams.names");
var a = queryParamNames.toArray();
var length = a.length;
context.setVariable('test_qparam_names_length', length);
var i = 0;
a.forEach(function(item) {
  context.setVariable('test_qparam_name_found' + i++, true);
  context.setVariable('test_qparam_name_' + i++, item.toString());
});

For my own purposes, it is easier to use the string manipulation approach, or to use the URI.js library. YMMV.

Thanks @Dino for the answers, they are to my satisfaction. So basically if the JavaObject returned is a JS wrapper of the Java Collection interface then there is a way we could leverage this. As you posted in your example of using .toArray(); which is a Java method in the Colleciton interface, we might as well can use .contains(); to check if a parameter is found inside it. This what I needed to do anyways.

So actually if you check out http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html and use those exposed methods, you can use the Set more efficiently. This should be reflected in the documentation too.

Yes, @Georges Haddad , good suggestion. We should update the documentation appropriately. I agree completely that the current statement - "this variable returns a variable of type Collection" - needs to be clearer. We will do that and get back to you.

@docs @sgilson @Floyd Jones, For your reference, Can we provide a link to this discussion page from Variable Reference Documentation page in "message.queryparams.names" section & update docs as needed? Thank you 🙂

Thank you @Anil Sagar, @Dino, and @Georges Haddad! I'm working on this documentation update and will post to this inquiry once the content has been published. Appreciate all of the help with identifying the fix.

Not applicable

Hi,

I've found that the 'array' given by

var tmp = context.getVariable("request.queryparams.names");
var qp = qparams.toArray();

is indeed an iterable array; so doing

// this *does* print the first element
print("qp[0]: " + qp[0]);
// but..
print("type of param: " + typeof(q2[0]);
// prints 'object', not 'string'
print("type of param: " + typeof(q2[0].toString());
// also.

if ( q2[0] == 'xx' ) {..}
// Always fails (actually I'm using Sets to do compulsory/optional param validation but this holds)


*However*... if you do

if (q2[0] + "" == 'xx')

then you win.

I'm happy and disturbed...

Not applicable

The URI.js library has a function, hasQuery(queryparamname) function that returns true if the queryparamname exists in the URI query string.