Webhook with optional parameters or NULL

Hello,

I have an API endpoint which has a bunch of optional parameters. I can either not include the parameter or send NULL. These parameters are a mixture of integers and strings. However, looking at…

It seems the webhook variables types are predefined when creating a webhook (i.e. quotes give a string and no quotes give an integer/float etc…). This means if I want to send NULL into a string variable, it gets cast as a string and if I want to send NULL as an integer it becomes a 0.

I also found GitHub - rickkas7/particle-webhooks: Particle Webhooks Intermediate Tutorial which talks about conditional blocks in the web hook’s body. I’ve tried this but so far I have not been able to get the conditions working. Has anyone been able to get optional parameters working with particle web hooks?

Sample of web hook configuration:

  • Type: Post
  • Format: JSON
  • JSON Data:
{
    {{{#variable1}}}
        "variable1": "{{{variable1}}}",
    {{{/variable1}}}
    
    {{{#variable2}}}
        "variable2": {{{variable2}}},
    {{{/variable3}}}
    
    {{{#variable3}}}
        "variable3": "{{{variable3}}}",
    {{{/variable3}}}
    }

  "version": {{{PRODUCT_VERSION}}}

Note variable1 and variable3 are strings and variable2 is an integer.

Sample publish code on firmware:

  • Note I am using JsonParserGeneratorRK to generate the json
    JsonWriterStatic<1024> body;
    body.init();
    body.startObject(); // Start 0
    switch (mode) {
        case 0: // Just send variable1
            body.insertKeyValue("variable1", variable1);
            break;
        case 1: // Just send variable 2 and 3
            body.insertKeyValue("variable2", variable2);
            body.insertKeyValue("variable3", variable3);
            break;
    }
    body.finishObjectOrArray(); // End 0
    body.nullTerminate();
    Particle.publish(webhook, body.getBuffer(), PRIVATE);

If I publish using mode 1 expect to publish just {"variable1":"variable1"}, however on the backend I am getting…

{
    "variable1": "variable1",
    "variable2": ,
    "variable3": "",
    "version": 10
}

Just wondering if someone could point out what I am doing wrong.

I am on deviceOS 2.0.1 but I don’t think it should matter in this case.

A work around I have is to create multiple webhooks for the same endpoint. However this quickly becomes a hassel.

I believe the reason that it does not work is the conditional block is not only conditional on the key being present, but it also descends into the key and uses that as a relative reference.

In the intermediate webhooks example, note the use of {{c}} even though the actual JSON is {{b.c}} because it’s contained in a {{#b}}.

I don’t know of a way to make a conditional test on presence of a key to value, instead of a key to a nested object.

@rickkas7 thanks for the information and explanation.

With regards to my situation, do you see any alternatives besides making multiple web hooks? Multiple web hooks for a single API end point is fine it just becomes a hassel to manage and does not seem very elegant to me.

One option is to create the modes as objects within the JSON object.

So you publish either this:

{
  "m0": {
    "variable1":"xx"
  }
}

Or this:

{
  "m1": {
    "variable2":123,
    "variable3":"abc"
  }
}

You generate that using in the switch statement:

case 0: // Just send variable1
        jw.insertKeyObject("m0");
        jw.insertKeyValue("variable1", variable1);
        jw.finishObjectOrArray();
        break;
case 1: // Just send variable 2 and 3
        jw.insertKeyObject("m1");
        jw.insertKeyValue("variable2", variable2);
        jw.insertKeyValue("variable3", variable3);
        jw.finishObjectOrArray();
        break;

Then in the webhook you can use:

{
    {{#m0}}
        "variable1": "{{{variable1}}}"
    {{/m0}}
    
    {{#m1}}
        "variable2": {{{variable2}}},
        "variable3": "{{{variable3}}}"
    {{/m1}}
}

I didn’t test it, but it probably should work.

@rickkas7 noted, if this is done, on the backend will we also recieve the JSON with the nested mode object? Example, i send just m1, I assume we will recieve:

{
  "m1": {
    "variable2":123,
    "variable3":"abc"
  }
}

The desired ideal result would just be variables2 and variables3 but if m1 is also sent I can talk to the backend team to see if they can accomodate the change. There also maybe issue with compatibility legacy devices on our side since variable2 and variable3 are new variables introduced in newer versions of our firmware, so if m1 is also send this maybe an issue.

Just trying to gather all the pieces before I proceed.

The backend should not receive m0 and m1 as the webhook will remove them as part of the conditional/nested block in mustache.

In the case that m1 is present the backend should get

{
    "variable2":123,
    "variable3":"abc"
}

@rickkas7 perfect, that is good news, I will test this out today. Thanks a lot for the quick response as well as your article on conditional blocks.

@rickkas7 I tried this out today and so far it seems to be working. Still working through it.

Just a few questions:

  • On the particle Webhook editor, what is the difference between using double {} and triple {} for variables? On the tutorial it seems triple {} are used but it seems the conditional blocks only work with double {} (i.e. {{variable}} vs {{{variable}}})
  • The conditional blocks present basically means if m0 present then include this, is there a way to do and equalivent of an else statement if m0 is not present?

Hello,

So we finalized the solution to my problem and the conditional block does help. However we still had to split the APIs due to limitations of the conditional block.

The problem here was that we actually had 3 cases. In 1 scenario, we wanted variable1 to always be returned and in scenario 2 we wanted variable1 with an optional variable2, so something like:

{
    {{#m0}}
        "variable1": "{{{variable1}}}",
    {{/m0}}
    "variable2": {{{variable2}}}
 }

In the last case we wanted variable3 and variable4 to be returned. i.e.:

{
    "variable3": {{{variable3}}},
    "variable4": {{{variable4}}}
}

Our older firmware only supported constantly returning variable1 with no objects within the JSON object so we could not take into account variable3 and variable4 even if our newer firmware added the object to make variable2 optional. So we split the APIs into 2 web hooks as per above.

A better flexible solution to solve the problem above with 1 webhook with backwards compatibility would actually have the particle webhooks not have any of these JSON mappings and just forward whatever string is given by the firmware. The backend recieving this call will be able to parse and deal with these variables with whatever logic they want. There are advantages to the mapping like pre-define variables etc… but I think the option to have no mapping is a useful one too.

I guess one way to by pass this mapping would be to pass a string into a single JSON variable and this string itself is a parsable JSON, but that seems a bit messy.

Overall the conditional blocks by @rickkas7 helped so I am marking his post as a solution. The blocks allowed us to split the APIs 2 ways instead of 3 ways and deprecating the API with just variable1.

@rickkas7 let me know if you have any comments.