[webhook] New, very simple binding for listening incomming http requests

I just did the update from 4.1.x to 4.2.2, and in my case the binding worked right away after the update.

Ok something must be different with my setup.
Whenever I upgrade OH I need to reinstall the binding from market place. Anybody know what could be the cause? All other bindings are working fine after upgrade

That is by intention. You have to reinstall marketplace binding everytime a cleancache happens, including an openhab update

Hi Piotr,
I have an eKey device which sends a json string via http post.
Unfortunately it adds to the URL its own path suffix so that the complete URL looks like this:

https://openhab:8443/webhook/thingname/itemname/api/notification/finger

Where /api/notification/finger is added by the ekey system.

Do you have an idea if your binding can catch this request?

Though I am not the developer, I have the webhook running and did a short test: it seems you‘d be good, if the stuff added is separated from the thing with a / it is ignored. You can even add parameters (thingname/whatever/blah?x=y and they are still processed and available in the executed script.

Interesting. I did test this but my result was negative. Let me re-test again…

Did some more testing and it is not working. Probably you are using an approach which I cannot use for my system.

I am only able to provide a URL. I have no access to the content. That is being added to the request body of the http POST request in the background.

The URL I can provide looks like this:

https://openhab:8443/webhook/thingname/itemname

I cannot make it like this:

https://openhab:8443/webhook/thingname?itemname=xyz

as I have no access to the xyz string.

EDIT:
Getting closer: req.body.text needs to be entered as the channel expression. This works when payload is a simple string but req.body.json does not work for json.

Is the “itemname” an information you need in the Webhook JEXL script in OH, or can it just be ignored? I am not sure if there is a way to process parts of the URL in the JEXL script.

I am afraid that is something I have not tried, maybe someone else can help.

I have written a JEXL script that basically puts everything provided by the Webhook binding into a JSON and then passes it on to a JavaScript rule for processing. I also include req.body.json, but I never tested if it actually works.

UID: webhook:Webhook:d1097152a4
label: Webhook
thingTypeUID: webhook:Webhook
configuration:
  expression: resp.status=200
channels:
  - id: lastCall
    channelTypeUID: webhook:lastCall-channel
    label: Last request
    description: Timestamp of the last request to the webhook.
    configuration: {}
  - id: trigger
    channelTypeUID: webhook:trigger-channel
    label: Trigger
    description: Trigger that fires for each incoming request.
    configuration:
      expression: >-
        {
          // This expression takes all data from the request and puts it into a JSON string
          var gson = new( "com.google.gson.Gson" );
          var jsonRoot = {:}; var jsonBody = {:};
          // If text/json are not present put returns an error, so we need to check first
          if( ! empty( req.body.text ) ) jsonBody.put( "text", req.body.text );
          if( ! empty( req.body.json ) ) jsonBody.put( "json", req.body.json );
          jsonRoot.put( "parameters", req.parameters );
          jsonRoot.put( "body", jsonBody );
          jsonRoot.put( "method", req.method );
          return gson.toJson( jsonRoot );
        }

The JavaScript that is triggered by the event channel then simply opens with the following line and continues to process the data:

var request = JSON.parse( event.event );

I had same spare time this morning and tested it, for me req.body.json works. I used Postman to POST a request with content type “application/json” and the body content ended up both in req.body.json and req.body.text in the JEXL.

Here is my Postman request:

The cURL command generated by Postman looks like this:

curl --location 'https://home.myopenhab.org/webhook/d1097152a4' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--header 'Cookie: CloudServer=10.11.0.33%3A3001; X-OPENHAB-AUTH-HEADER=true' \
--data '{"test":"test"}'

The JEXL I posted in my previous post produces this output that can be processed in the triggered JavaScript rule:

{"body":{"json":{"test":"test"},"text":"{\"test\":\"test\"}"},"method":"POST","parameters":{}}

Hi Robert,
first of all thank you very much for your assistence.

I also did some more testing and it turns out that probably the device has some problems with authorization.
When sending an https request including bearer token I think that sometimes the request gets thrugh to openhab and sometimes not. Only if I switch to http without authorization, then the request gets through to the jexl script and

req.body.json

works now without a problem.

Again, thank you very much for your support.

Hey Robert,
I experienced a character replacement of the json string.

The original JSON string looks like a regular json object:

{"key1": "value1",
 "key2": "value2"}

which I can confirm as I have sent the request to a different server.
However, when the string is returnd by the webhook binding, the structure looks like this:

{key1=value1,
 key2=value2}

Did you also come across this unwanted conversion?

No, in my testing req.body.json came out as expected:

{"test":"test"}

How does your JEXL look like exactly? The conversion you see in your rule that processes the data? Maybe you could post that code too? What is the Content-Type of your HTTP request?

Content type is application/json
The jexl script just has one line:
return req.body.json

I didn‘t even start with a rule. It is the item which shows my the conversion.

Maybe try just
return req.body.text

req.body.json gives you an actual object to navigate through json properties when the request payload contains such json file. However, returning the json object converts it to string which can give you unexpected results.

In my case also converting req,body.json to a string gives me a properly formatted JSON.

So maybe the JSON object from req.body.json is assigned to the item and then is converted on display? Do you actually need an item? You can also trigger the rule directly from the thing channel:

Thanks Piotr and Robert @the-ninth,
Indeed, I need to use
req.body.text

Then there is no conversion.

Does anybody of you know of a jexl command or function, so that I can convert the req object into a string (incl. keys and values)? (this will make testing and analyzing easier)
Is it possible to log some information into openhab log file?

The JEXL script I posted further above is doing exactly that, it builds a JSON string out of the whole req object. You gan trigger a JavaScript from the thing and then print the JSON there into the log.

Sorry, I was too unprecise. Your script requires that you know in advance which keys within the req object are available (parameters, body, method).
I am thinking more of a generic dump of the req object or a function which loops through all keys (where we currently are aware of just three). Maybe there is more information available?

Ah, understand. I think that was a bit quirky. req.parameters can be put into the JSON structure and all its items are added. For req and req.body as far as I remember that did not work. Otherwise my JEXL would have been much simpler.

But you could still give this JEXL code a try and see what happens:

var gson = new( "com.google.gson.Gson" );
return gson.toJson( req );

Another thing you could try is to iterate with JEXL for over req and put each element you find in the JSON structure. You can find info on the JEXL for on the page linked below.

Edit: however you may need to do this recursively, and doing that within that JEXL code may be a bit messy …

I think already earlier people reported here that they had to reinstall the binding after OH updates?

I did not have that issue before but since OH 4.3 I do. Did two updates since 4.3 was released, and in each case the binding was not installed anymore after the update, I had to go to the add-on store and install it again.

Any ideas what may be causing this issue?