Parse(), parseRequired() and parseOptional in custom module .js

This does not appear to be documented anywhere so hopefully this will clear up my questions and also act as a reference document. Here is my understanding and questions at the end.

When creating custom extensions there are 3 main ways to parse dynamic data

So, for example, if we have a a query called "query1" passed from a module via the HJSON interface from an input named "myquery" options, then options.myquery would return

"query1".

To obtain the actual data this must be parsed to get the dynamic content

1. The must basic method is simply:

this.parse(options.myquery)

This is simple enough and will parse the input "input" returning the JSON of the query named "query1" like

{ "id" : 1, "name" : "Brian"}

2. Additionally we have:

this.parseRequired(options.myquery)

ParseRequired is used like this:

const queryParsed = this.parseRequired(options,myquery, 'string', 'query parameter is required.');

This will parse the query in the same way as (1) but will throw an error if the parameters is missing/ cant be parsed.

Note there are 3 parameters, the myquery, a data type and error message. (question about this below)

3. Lastly there is parseOptional()

parseOptional() is used like this

const queryParsed =this.parseOptional('myquery', 'string', 'defaultvalue')

In this case 'query1' is parsed as above but if not successfully parsed, a default value is set in it's place.

I have actually used these methods successfully in the past but always felt i was not 100% confident in relation to some points so here it comes.

So my questions are:

  1. is the above a correct summary?
  2. Does the data type apply to the expected datatype of the incoming data to options.myquery.
  3. Are all data types allowed?
1 Like

Your summary is correct, will try to give a short description of the 3 method here.


this.parseRequired(option, type, errorMessage)

option: the option you want to parse, this can be a static value or an expression.
type: the type of the option, this is a javascript type returned by typeof and an error is thrown wenn it doesn't match. use '*' to match any type.
errorMessage: the error message that is thrown when the option is missing or of the wrong type.


this.parseOptional(option, type, defaultValue)

option: the option you want to parse, this can be a static value or an expression.
type: the type of the option, this is a javascript type returned by typeof and default value is returned when type is invalid. use '*' to match any type.
defaultValue: the value to return when the option is missing or of the wrong type.


this.parse(option, scope)

option: the option you want to parse, this can be a static value or an expression. you can also give it the whole options object and it will recursive parse all properties.
scope: optional you can give it a different datascope, default the current scope is used.


Sample using all methods:

exports.fullname = function(options) {
  // parse required option user which must be an object
  const user = this.parseRequired(options.user, 'object', 'User is required');
  // parse optional template option
  const template = this.parseOptional(options.template, 'string', '{{firstname}} {{lastname}}');
  // create a new scope extending the current with the user object
  const scope = this.scope.create(user);
  // parse the template with the new scope
  return this.parse(template, scope);
}

So the second parameter (datatype) is the data type of the input (option.input) being passes to parse() rather than converting the output to that data type?

And what is this.scope?

Yes, it is a validation check, it doesn't convert the input value.

this.scope is the current scope the app is in, this.scope.create creates a sub scope on the current scope and returns that, so all data on the parent scopes are also accessible.

Scopes are like nested objects of data. When you have an expression like {{user.id}} it will look for the user key in the current scope, if it can't find the key it will go up to the parent scope and look there until it is at the root scope. If it isn't found undefined is returned otherwise it will return the user object which then is further parsed and the id of the user object is then returned. The properties of the object passed to the subscope become keys, so you can acces them directly like {{firstname}} within that subscope.

1 Like

Thanks again, think i follow it, will find out soon enough!

1 Like

Is that a database query step? You're not supposed to parse the result of that, it's already executed, the output is pure JSON with no expression to parse, right?

Did you overcomplicate the example?

Hmm, strange, that's not what i have observed

as an example

I pass a query to a module and output the raw option

exports.apple = async function (options) {
    return options.myquery;

}

i see browser output of:

{
Apple1: "{{query1}}"
}

I then return the parsed query and log the sent data

exports.apple = async function (options) {
    console.log("Raw Query: " + options.myquery);
    parsedValue = this.parse(options.myquery);
    return parsedValue;
}

i see the data in the browser:

{
Apple1: {
people_id: 1,
surname: "English",
forname: "Brian",
email: "brian@hyperbytes.co.uk"
}
}

and in the console i can see

Raw Query: {{query1}}

Sorry, should have included the API action

You're right, my bad

1 Like

No problem, you took the time to think about it and thats the important issue. We are all entitled to a bad day/ senior moment and get it wrong from time to time. I have so much personal experience of that!

1 Like