N
n8n Store
Workflow Market
WebhookDocs: generate swagger preview of your active workflows

WebhookDocs: generate swagger preview of your active workflows

by dangerblack0 views

描述

分类

🔧 Engineering

使用的节点

n8n-nodes-base.n8nn8n-nodes-base.coden8n-nodes-base.webhookn8n-nodes-base.stickyNoten8n-nodes-base.respondToWebhook
价格免费
浏览量0
最后更新11/28/2025
workflow.json
{
  "meta": {
    "instanceId": "d68b0885df4f6057c27649c0cc1cdbf154a8c3c6de34051d82d8f9164d66f031",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "1f397969-aa2e-435b-b0e9-9ef66face5fc",
      "name": "n8n",
      "type": "n8n-nodes-base.n8n",
      "position": [
        220,
        100
      ],
      "parameters": {
        "filters": {
          "activeWorkflows": true
        },
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "id": "23",
          "name": "n8n account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "37b03898-8b7b-4511-8a54-b6777118ea76",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        440,
        100
      ],
      "parameters": {
        "jsCode": "function safe(x) \n{\n  return x.replaceAll(\":\",\"\").replaceAll(\"/\",\"|\")\n}\n\nfunction findValidTargets(connections, sourceNode, potentialTargets) {\n  const visited = new Set();\n  const foundTargets = new Set();\n\n  function dfs(node) {\n    if (visited.has(node)) return;\n    visited.add(node);\n\n    if (potentialTargets.includes(node)) {\n      foundTargets.add(node);\n      return; // Optionally continue search if multiple paths to same target are needed\n    }\n\n    const nodeConnections = connections[node]?.main || [];\n    for (const path of nodeConnections) {\n      for (const next of path) {\n        dfs(next.node);\n      }\n    }\n  }\n\n  dfs(sourceNode);\n  return Array.from(foundTargets);\n}\n\nconst nodes = []\nfor (const item of $input.all()) \n{\n  let webhook = {\n    name: item.json.name,\n    id: item.json.id,\n    webhooks: []\n  }\n  const webhook_call = item.json.nodes.filter(node =>node.type=='n8n-nodes-base.webhook');\n  const webhook_resp = item.json.nodes.filter(node =>node.type=='n8n-nodes-base.respondToWebhook');\n  const targets = webhook_resp.map(wr => wr.name);\n  if(webhook_call.length)\n  {\n    for(const call of webhook_call)\n    {\n        const callName = call.name;\n        if(call?.parameters?.responseMode == \"responseNode\")\n        {\n            const valid = findValidTargets(item.json.connections, callName, targets);\n            call.responses = webhook_resp.filter(wr => valid.includes(wr.name))\n        }\n    }\n    \n      webhook.webhooks.push(...webhook_call);\n      nodes.push(webhook);\n  }\n}\n\nlet s = `\nswagger: \"2.0\"\ninfo:\n  title: N8N Instance API\n  description: API description in Markdown.\n  version: 1.0.0\n  \nhost: ${$('Get Swagger').first().json?.headers?.host || 'n8n.instance.com'}\n\nbasePath: /webhook\nschemes:\n  - https\npaths:\n`\n\nfor(const node of nodes)\n{\n    const used_path = {};\n    for(const w of node.webhooks)\n    {\n      let path = '';\n      if(!(w?.parameters?.path in used_path))\n      {\n        path = w?.parameters?.path;\n        used_path[path] = true;\n      }\n\n      let produces = \"application/json\"\n      let code = 200;\n      if(w?.responses?.length)\n      {\n          for(const r of w.responses)\n          {\n              switch(r?.parameters?.respondWith)\n              {\n                case 'text':\n                  produces ='text/plain';\n                break\n                case 'redirect':\n                  produces = 'redirect';\n                  code = 301\n                break\n                case 'json':\n                  produces = 'application/json';\n                break\n              }\n          }\n      }\n      let parameters = []\n      if(w?.notes)\n      {\n        console.log({notes: w.notes})\n        const params = w?.notes?.split('\\n').filter(p => p.startsWith('@'));\n        for(const p of params)\n        {\n          const parts = p.split(' ');\n          const [position, name, type] = parts;\n          const description = parts.slice(3).join(' ');\n          console.log(p.split(' '))\n          switch(position)\n          {\n            case '@query':\n              parameters.push(`\n        - name: ${name}\n          in: ${position.replaceAll('@', '')}\n          description: ${description || 'no description'}\n          type: ${type}\n          required: true\n`)\n            break\n            case '@body':\n              parameters.push(`\n        - name: ${name}\n          in: ${position.replaceAll('@', '')}\n          description: ${description || 'no description'}\n          schema:\n            type: object\n            required:\n              - ${name}\n            properties:\n              ${name}:\n                type: ${type}\n`)\n          }\n        \n        }\n\n        if(parameters.length)\n        {\n          parameters.unshift(`\n      parameters:\n`)\n        }\n      }\n      s+=`\n  ${path ? `/${path}:` : ''}\n    ${w?.parameters?.httpMethod?.toLowerCase() || 'get'} :\n      summary: ${safe(w?.name) || safe(node.name)}.\n      description: Related to workflow [${node.id}].\n      tags:\n        - ${safe(node.name)}\n      ${parameters.join('\\n')}\n      produces:\n        - ${produces}\n      responses:\n        ${code}:\n          description: OK`\n    }\n}\n\nreturn {json:{text: s, nodes}};"
      },
      "typeVersion": 2
    },
    {
      "id": "872dbe8f-a4e2-4828-98d5-73f06ae116ad",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        660,
        100
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "=<!DOCTYPE html>\n<html>\n<head>\n  <title>Swagger UI from YAML Text</title>\n  <link rel=\"stylesheet\" href=\"https://unpkg.com/swagger-ui-dist/swagger-ui.css\">\n</head>\n<body>\n  <div id=\"swagger-ui\"></div>\n\n  <script src=\"https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js\"></script>\n  <script src=\"https://unpkg.com/[email protected]/dist/js-yaml.min.js\"></script>\n  <script>\n    // Your YAML as a string (replace this with your actual variable)\n    const yamlText = `{{ $json.text }}`;\n\n    // Parse the YAML into a JavaScript object\n    const spec = jsyaml.load(yamlText);\n\n    // Initialize Swagger UI with the parsed spec\n    const ui = SwaggerUIBundle({\n      spec: spec,\n      dom_id: \"#swagger-ui\"\n    });\n  </script>\n</body>\n</html>\n"
      },
      "typeVersion": 1.2
    },
    {
      "id": "7868c867-85c4-422d-a9f3-7424af49fd14",
      "name": "Get Swagger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        100
      ],
      "webhookId": "b6873bae-3e61-4a93-9dc2-0100b497390e",
      "parameters": {
        "path": "swagger",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "30aa0403-c828-48eb-862b-4b258249c1e1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -160
      ],
      "parameters": {
        "width": 480,
        "height": 180,
        "content": "## Configure webhooks\n\nIn order to support parameter labels you have to open the note sections of every webhook and add the following text\n\n//@body field_name string description\n//@query field_name string description\n\n"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "n8n": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Swagger": {
      "main": [
        [
          {
            "node": "n8n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

相关工作流