Control the node to respond a WebHook

In a webhook, I’m having difficulties getting right the response mode of Last Node with the First entry JSON.

This webhook workflow that is a bit complex. It has around 60 nodes by now, and many of these are nodes that execute other workflows that I’m not counting.

My difficulty, and source of many bugs, is predicting that the last node to be executed correctly is the one I suppose.

For example, in the flow of the nodes, many times I have a Set node to build the json response. But it may have a parallel flux that sends a message but it doesn’t have to wait to finish to return. The problem is that sometimes it takes the output from this message sending node instead of the one I set up to return. I’m fixing using a merge node with a pass-through, that will wait for the output of the message sending node and the main flow to send just the main flow forward.

I tried to use things like No-Op nodes and others to kill the output chain, so the branch is executed but in the end they don’t set any output, but I got no luck.

In this minimal workflow, I have to nodes to set the response, one returning a and the other returning b. The webhook always returns the b, no matter what I do, I cannot change who is chosen by the webhook.

{
  "name": "webhook reponse test",
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        300,
        350
      ]
    },
    {
      "parameters": {
        "path": "hello",
        "responseMode": "lastNode",
        "responseData": "allEntries",
        "options": {}
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        300,
        200
      ],
      "webhookId": "f8e9855d-3b50-4770-bda2-f772cf5f51d8"
    },
    {
      "parameters": {
        "functionCode": "for(i=0; i<1000; i++);\nreturn item;"
      },
      "name": "Lag",
      "type": "n8n-nodes-base.functionItem",
      "typeVersion": 1,
      "position": [
        500,
        310
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "from.b",
              "value": "b"
            }
          ]
        },
        "options": {}
      },
      "name": "Set B",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        680,
        310
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "from.a",
              "value": "a"
            }
          ]
        },
        "options": {}
      },
      "name": "Set A",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        500,
        150
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Set A",
            "type": "main",
            "index": 0
          },
          {
            "node": "Lag",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lag": {
      "main": [
        [
          {
            "node": "Set B",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {},
  "id": "13"
}

I tried to read and debug the code that decides this but I didn’t get much farther.

Is there any way to control this in a scalable way? Today’s ways add a lot of complexity.

Proposal

I also was thinking about creating a flag for the nodes, like the one in the settings of a node (eg: Always Output Data), that would help to control who may or may not be used in the webhook return.

It’s a simple addition that could help a lot to reduce the risks of workflow bugs, complexity, and scalability for big webhook workflows.

I think something like a boolean Webhook response, and that if there is any node with this flag on, it will filter the results to include only the nodes with that flag. Otherwise, if none of the nodes has it on, then it works just like it does now. This way helps reducing changes of bugs caused by a node that you created and create an output, but you forgot to filter out.

I willing to implement this myself, so, how does this idea sound?

You are right. That is currently not perfect and returning before the workflow is done is not possible.

I really want to avoid adding more “flags” (there are already too many) esp. if they do not do anything at all in very many workflows (literally in all which do not have a webhook). On top do we not just have to consider the actual response-body also the response-code (Webhook - modify response code based on criteria) and response-headers. All of them should be able to be set dynamically at a later point. So the “flag” would also not help in that regard.

We do not have the perfect solution for that yet but something which seems to be more suitable would be a specific Webhook-Response-Node. On it all the response data could then be set accordingly, as soon the first node of that type gets hit, it returns the data and that allows then still the workflow to continue executing even after the response got send.

Does that make sense?

1 Like

Webhook-Response-Node sounds just like the solution that we also need. Assuming it would also allow for setting the response headers along with the response data.

1 Like

That makes sense.

Thinking from where I’m coming from, one thing I would like is to not have to add more nodes to the end of the branches. I usually use Set nodes with Keep Only Set and Dot notation to build the JSON response. But a node of the kind you said could easily do that and much more.

Next week I think I will be able to start playing with building such node. I may need some help in some points, as this would not only need a new node but change the n8n itself (like in cli/src/WebhookHelpers.ts), as the handling of the response for webhooks isn’t in the webhook nodes itself.

Sounds great. Thanks!

Yes, is for sure much more work than a regular node as it would need quite some core changes as you mentioned. It is also important to keep that solution generic. Meaning not just thinking about returning data for webhooks, also implementing it in a way that it can be used by other systems which work similarly. For example, for a queue to acknowledge that the message got consumed successfully. Can see very many use cases where that functionality could be important.

Sure simply reach out if there is anything!