使用 n8n API 和 Bootstrap 为 Webhooks 生成自文档化 API 门户
高级
这是一个Document Extraction, Multimodal AI领域的自动化工作流,包含 17 个节点。主要使用 N8n, Set, Code, Html, Webhook 等节点。 使用 n8n API 和 Bootstrap 为 Webhooks 生成自文档化 API 门户
前置要求
- •HTTP Webhook 端点(n8n 会自动生成)
使用的节点 (17)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "e860732ed76ff1de8212e780b2d62bd140dee0b71e6ccf7172d54e965acae43d",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "a59b516a-e188-4364-8722-f83fd00ed0f0",
"name": "聚合",
"type": "n8n-nodes-base.aggregate",
"position": [
120,
-300
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1
},
{
"id": "3ab41431-6298-4380-aaec-d0e29f7f9cb5",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-700,
460
],
"webhookId": "e98f9bf5-f5ad-46fb-a93c-08218eea8d5e",
"parameters": {
"path": "api-doc",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "286e23f0-44c8-46c4-bfd2-8aab6eae245b",
"name": "配置",
"type": "n8n-nodes-base.set",
"position": [
-480,
460
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9a243289-a359-47fd-9155-a809a910b8f7",
"name": "name_doc",
"type": "string",
"value": "N8N Example Doc"
},
{
"id": "59992f15-d27d-454c-9c1f-a66f0674c7bb",
"name": "version",
"type": "string",
"value": "v.0.1"
},
{
"id": "f0633ecb-b0c8-4e55-8285-51aa05492420",
"name": "description",
"type": "string",
"value": "Example description"
},
{
"id": "2da37a16-f97a-4ec8-9d9c-13f09bea1d39",
"name": "url_base",
"type": "string",
"value": "n8n.io/"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b910c088-c3c6-4bfc-9856-5294891e4cd0",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-370,
-400
],
"parameters": {
"color": 2,
"width": 860,
"height": 260,
"content": "## 获取工作流并筛选"
},
"typeVersion": 1
},
{
"id": "add44468-ffba-401e-a119-3e25c4870ece",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-360,
-120
],
"parameters": {
"color": 6,
"width": 760,
"height": 400,
"content": "## 用于测试的 webhook"
},
"typeVersion": 1
},
{
"id": "1de3f20f-152c-4f81-b42d-cc9e03f5bf0d",
"name": "响应",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
120,
-40
],
"parameters": {
"options": {},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.1
},
{
"id": "0a7a9d55-5b34-4129-952d-c982ebcc3d7c",
"name": "HTML响应",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
180,
460
],
"parameters": {
"options": {},
"respondWith": "text",
"responseBody": "={{$json.html}}"
},
"typeVersion": 1.1
},
{
"id": "f85d91a0-16ec-4f79-870a-dfc24f954469",
"name": "生成完整HTML",
"type": "n8n-nodes-base.html",
"position": [
-40,
460
],
"parameters": {
"html": "<html>\n<head>\n <title>{{$('Configs').item.json.name_doc}}</title>\n <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css\">\n <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n <style>\n :root {\n --bs-body-bg: #1a1a1a;\n --bs-body-color: #e0e0e0;\n --bs-border-color: #444;\n --bs-accordion-bg: #2b2b2b;\n --bs-accordion-color: #e0e0e0;\n --bs-accordion-button-color: #e0e0e0;\n --bs-accordion-border-color: #444;\n --bs-accordion-button-active-bg: #3c3c3c;\n --bs-accordion-button-active-color: #ffffff;\n --bs-accordion-button-focus-border-color: #007bff;\n --bs-accordion-button-focus-box-shadow: 0 0 0 0.25rem rgba(0, 123, 255, 0.25);\n }\n .method {\n display: inline-block;\n padding: 0.3em 0.8em;\n border-radius: 0.25rem;\n font-weight: bold;\n font-size: 0.9em;\n color: white;\n text-transform: uppercase;\n margin-right: 1rem;\n }\n .method-post { background-color: #49cc90; }\n .method-get { background-color: #61affe; }\n .endpoint-path {\n font-family: monospace;\n font-size: 1.1em;\n color: #ccc;\n }\n pre {\n background-color: #161B22;\n padding: 1rem;\n border-radius: 0.25rem;\n white-space: pre-wrap;\n word-break: break-all;\n border: 1px solid var(--bs-border-color);\n }\n code { color: #c9d1d9; }\n .accordion-button:not(.collapsed) {\n box-shadow: inset 0 -1px 0 var(--bs-accordion-border-color);\n }\n </style>\n</head>\n<body class=\"p-4\">\n <div class=\"container\">\n <div class=\"d-flex align-items-baseline mb-4\">\n <h1 class=\"text-white me-3\">{{$('Configs').item.json.name_doc}}</h1>\n <p class=\"text-white-50 me-3\">{{$('Configs').item.json.description}}</p>\n <span class=\"badge bg-secondary\">{{$('Configs').item.json.version}}</span>\n </div>\n \n {{ $json.htmlContent || `\n<div class=\"alert alert-danger d-flex align-items-center mt-4\" role=\"alert\">\n <i class=\"bi bi-x-octagon-fill me-3\" style=\"font-size: 2rem;\"></i>\n <div>\n <h4 class=\"alert-heading\">Documentation Generation Failed!</h4>\n <p>An error occurred while trying to generate the API documentation from the sub-workflow.</p>\n <hr>\n <p class=\"mb-1\"><strong>Please check the following:</strong></p>\n <ul>\n <li>Ensure the sub-workflow (the one that generates the accordion) executed successfully and produced an output named <code>htmlContent</code>.</li>\n <li>Verify that at least one of your workflows is active and contains a correctly configured <code>API_DOCS</code> node.</li>\n <li>Check the n8n execution logs for more detailed error messages from the sub-workflow.</li>\n </ul>\n </div>\n</div>\n`}}\n\n\n </div>\n <footer class=\"mt-5 pt-4 text-center text-white-50\">\n <p>\n Created by <a href=\"https://www.linkedin.com/in/matheus-pedrosa-custodio/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"link-light text-decoration-none\">\n <i class=\"bi bi-linkedin\"></i> Matheus Pedrosa\n </a>\n </p>\n</footer>\n \n <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js\"></script>\n</body>\n</html>"
},
"typeVersion": 1.2
},
{
"id": "0bd66854-cf1b-46b5-ad75-e0d7ef9b71d4",
"name": "执行子工作流",
"type": "n8n-nodes-base.executeWorkflow",
"onError": "continueRegularOutput",
"position": [
-260,
460
],
"parameters": {
"options": {
"waitForSubWorkflow": true
},
"workflowId": {
"__rl": true,
"mode": "list",
"value": "y2xOdk7RyRoS2sgF",
"cachedResultName": "Documentation"
},
"workflowInputs": {
"value": {},
"schema": [
{
"id": "url_base",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "url_base",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
}
},
"typeVersion": 1.2
},
{
"id": "43a02f1b-9f18-4148-9705-2c3347997cfa",
"name": "执行",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
-320,
-300
],
"parameters": {
"workflowInputs": {
"values": [
{
"name": "url_base"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "91ad9f92-adf3-4a8c-af48-3d1e5cd06678",
"name": "获取工作流",
"type": "n8n-nodes-base.n8n",
"position": [
-100,
-300
],
"parameters": {
"filters": {
"tags": "",
"activeWorkflows": true
},
"requestOptions": {}
},
"credentials": {
"n8nApi": {
"id": "fTE1pX6nL40KSIdW",
"name": "n8n account"
}
},
"retryOnFail": true,
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "c28819b2-2e5d-4732-9a68-0d5045dcb59e",
"name": "筛选工作流",
"type": "n8n-nodes-base.code",
"position": [
340,
-300
],
"parameters": {
"jsCode": "const allWorkflows = $('Aggregate').last().json.data;\nlet html = '';\n\nconst documentedWebhookWorkflows = allWorkflows.filter(item => {\n if (!item.nodes || item.nodes.length === 0) {\n return false;\n }\n const hasWebhook = item.nodes.some(node => node.type === 'n8n-nodes-base.webhook');\n const hasDocsNote = item.nodes.some(node => node.type === 'n8n-nodes-base.set' && node.name === 'API_DOCS');\n return hasWebhook && hasDocsNote;\n});\n\n\nif (documentedWebhookWorkflows.length > 0) {\n html += '<div class=\"accordion\" id=\"docsAccordion\">';\n\n const n8nBaseUrl = $(\"Execute\").last().json.url_base || 'https://n8n.io/';\n\n for (const workflow of documentedWebhookWorkflows) {\n const docsNode = workflow.nodes.find(n => n.name === 'API_DOCS');\n\n if (docsNode) {\n const jsonString = docsNode.parameters.jsonOutput || JSON.stringify(docsNode.parameters.docsData);\n let docsData = {};\n let webhookNode = null;\n\n try {\n docsData = JSON.parse(jsonString);\n webhookNode = workflow.nodes.find(n => { return n.type === 'n8n-nodes-base.webhook' && n.name === docsData.webhook });\n } catch (e) {\n console.error(`Erro ao parsear JSON no workflow: ${workflow.name}`, e);\n continue;\n }\n\n if(webhookNode){\n const method = (docsData.method || \"POST\").toUpperCase();\n const uniqueId = webhookNode.parameters.path.replace(/[^a-zA-Z0-9]/g, '');\n\n // --- make CURL\n const fullUrl = `${n8nBaseUrl}webhook/${webhookNode.parameters.path}`;\n\n let curlCommand = `curl -X ${method}\\\\`;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n const requestBodyString = JSON.stringify(docsData.requestBody || {});\n curlCommand += `\n -H 'Content-Type: application/json' \\\\\n -d '${requestBodyString}' \\\\`;\n }\n curlCommand += `\n ${fullUrl}`;\n\n html += `\n <div class=\"accordion-item\">\n <h2 class=\"accordion-header\" id=\"heading-${uniqueId}\">\n <button class=\"accordion-button collapsed\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#collapse-${uniqueId}\" aria-expanded=\"false\" aria-controls=\"collapse-${uniqueId}\">\n <span class=\"method method-${method.toLowerCase()}\">${method}</span>\n <span class=\"endpoint-path\">/webhook/${webhookNode.parameters.path}</span>\n </button>\n </h2>\n <div id=\"collapse-${uniqueId}\" class=\"accordion-collapse collapse\" aria-labelledby=\"heading-${uniqueId}\" data-bs-parent=\"#docsAccordion\">\n <div class=\"accordion-body\">\n <p><strong>${docsData.summary || 'No summary'}</strong></p>\n <p>${docsData.description || 'No description.'}</p>\n <hr style=\"border-color: var(--bs-border-color);\">\n \n <h6>cURL Command:</h6>\n <pre><code>${curlCommand}</code></pre>\n \n <h6>Request Body:</h6>\n <pre><code>${JSON.stringify(docsData.requestBody || {}, null, 2)}</code></pre>\n <h6>Success Response (${docsData.successCode || 'N/A'}):</h6>\n <pre><code>${JSON.stringify(docsData.successResponse || {}, null, 2)}</code></pre>\n <h6>Error Response (${docsData.errorCode || 'N/A'}):</h6>\n <pre><code>${JSON.stringify(docsData.errorResponse || {}, null, 2)}</code></pre>\n </div>\n </div>\n </div>\n `;\n }\n }\n }\n html += '</div>';\n} else {\n html += '<div class=\"alert alert-info\">Nenhum endpoint documentado foi encontrado.</div>';\n}\n\nreturn [{\n json: {\n htmlContent: html\n }\n}];"
},
"typeVersion": 2
},
{
"id": "78526a12-613c-4530-9a6f-bb612036addf",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-940,
-400
],
"parameters": {
"color": 4,
"width": 540,
"height": 700,
"content": "### 实时 n8n API 文档生成器"
},
"typeVersion": 1
},
{
"id": "602d0cd7-558e-4360-b385-bf9824f9278b",
"name": "Webhook1",
"type": "n8n-nodes-base.webhook",
"position": [
-320,
-40
],
"webhookId": "15105da5-96ca-472f-a7db-2ddc2e8b0891",
"parameters": {
"path": "15105da5-96ca-472f-a7db-2ddc2e8b0891",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "6283f30d-d1eb-4a7b-9f97-73834d7c060f",
"name": "API_DOCS",
"type": "n8n-nodes-base.set",
"position": [
-320,
120
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"expose\": true,\n \"webhook\": \"Webhook1\",\n \"summary\": \"Title test\",\n \"method\":\"get\",\n \"description\": \"Hey community, look at this cool workflow I'm doing.\",\n \"tags\": [\n \"test\",\n \"tag_0101\"\n ],\n \"requestBody\": {},\n \"successCode\": 200,\n \"successResponse\": {\n \"status\": 200,\n \"message\": \"Workflow start\"\n },\n \"errorCode\": 400,\n \"errorResponse\": {\n \"status\": 500,\n \"message\": \"Workflow error\"\n }\n}"
},
"typeVersion": 3.4
},
{
"id": "57843c34-afb5-401e-86dc-8aa22c242263",
"name": "模拟响应",
"type": "n8n-nodes-base.code",
"position": [
-100,
-40
],
"parameters": {
"jsCode": "return {\n \"status\": 200,\n \"message\": \"Workflow start\"\n }"
},
"typeVersion": 2
},
{
"id": "29b6b6ea-917b-47a3-b8a1-ff017b0a10a5",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-940,
400
],
"parameters": {
"width": 150,
"height": 200,
"content": "### 创建文档页面"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Configs": {
"main": [
[
{
"node": "ExecuteSubWorkflow",
"type": "main",
"index": 0
}
]
]
},
"Execute": {
"main": [
[
{
"node": "GetWorkflows",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Configs",
"type": "main",
"index": 0
}
]
]
},
"Webhook1": {
"main": [
[
{
"node": "FakeResponse",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "FilterWorkflows",
"type": "main",
"index": 0
}
]
]
},
"FakeResponse": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
},
"GetWorkflows": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"MakeFullHTML": {
"main": [
[
{
"node": "RespondHTML",
"type": "main",
"index": 0
}
]
]
},
"FilterWorkflows": {
"main": [
[]
]
},
"ExecuteSubWorkflow": {
"main": [
[
{
"node": "MakeFullHTML",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 文档提取, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
GitHub 同步仪表板 - V2
具有提交历史和回滚功能的 GitHub 工作流版本控制仪表板
If
N8n
Set
+20
94 节点Eduard
开发运维
工作流统计
🦅 通过工作流仪表板全面概览您的n8n实例!
N8n
Set
Xml
+12
31 节点Eduard
开发运维
自动化订单确认,使用Abacate Pay:首购优惠券奖励,通过邮件和Slack
自动化订单确认,使用Abacate Pay:首购优惠券奖励,通过邮件和Slack
If
Set
Code
+6
13 节点Matheus Pedrosa
客户关系管理
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+93
113 节点I versus AI
其他
来自xlsx、xls或csv文件的智能报告生成器,具有基于AI的分析
使用Gemini AI和Google Workspace从Excel/CSV生成专业报告
If
Set
Code
+18
35 节点franck fambou
文档提取
实时Notion Todoist双向同步模板
使用Redis的Notion Todoist实时双向同步
If
Set
Code
+26
246 节点Mario
销售
工作流信息
难度等级
高级
节点数量17
分类2
节点类型10
作者
Matheus Pedrosa
@julinhoI am a software engineer specializing in automations, with extensive experience on the N8N platform. With solid skills in JavaScript, Go, .NET, and C#, I am equipped to develop efficient and scalable solutions.
外部链接
在 n8n.io 查看 →
分享此工作流