Créer une passerelle API dynamique avec des routages HTTP et une orchestration de workflow
Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 24 nœuds.Utilise principalement des nœuds comme If, Set, Code, Webhook, ExecuteWorkflow. Créer une passerelle API dynamique avec des routes HTTP et une orchestration de workflows
- •Point de terminaison HTTP Webhook (généré automatiquement par n8n)
Nœuds utilisés (24)
Catégorie
{
"meta": {
"instanceId": "2af7d602b9c59038b521d73a8d986df022306cc34b7d66460334237434b5f4ad"
},
"nodes": [
{
"id": "e6445f6f-1087-4e51-b8e5-ddb99456f868",
"name": "HEAD",
"type": "n8n-nodes-base.set",
"position": [
-336,
1440
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"method\": \"HEAD\"\n}\n"
},
"typeVersion": 3.4
},
{
"id": "bb48dadb-e960-4e34-bb51-f0a0528c0369",
"name": "Exécuter le flux de travail",
"type": "n8n-nodes-base.executeWorkflow",
"onError": "continueErrorOutput",
"position": [
896,
672
],
"parameters": {
"mode": "each",
"options": {
"waitForSubWorkflow": true
},
"workflowId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Resolve').item.json.workflowIdToExecute }}",
"cachedResultUrl": "/workflow/=%7B%7B%20$('Resolve').item.json.workflowIdToExecute%20%7D%7D"
},
"workflowInputs": {
"value": {},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
}
},
"typeVersion": 1.3
},
{
"id": "050ed363-ea07-4301-a53b-28c5c6328857",
"name": "Succès",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1088,
672
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={{ $json }}"
},
"typeVersion": 1.4
},
{
"id": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"name": "Agréger les branches de méthode",
"type": "n8n-nodes-base.set",
"position": [
-128,
672
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={{ $json }}"
},
"typeVersion": 3.4
},
{
"id": "3bdd165b-3ce6-4292-b696-bfc99a984ee3",
"name": "PUT",
"type": "n8n-nodes-base.set",
"position": [
-336,
1280
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"method\": \"PUT\"\n}\n"
},
"typeVersion": 3.4
},
{
"id": "3aeaa1f4-9b71-46da-ae4f-277a356c1dc2",
"name": "PATCH",
"type": "n8n-nodes-base.set",
"position": [
-336,
1120
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"method\": \"PATCH\"\n}\n"
},
"typeVersion": 3.4
},
{
"id": "56b8e967-39b4-43d4-b610-77e009227d07",
"name": "DELETE",
"type": "n8n-nodes-base.set",
"position": [
-336,
960
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"method\": \"DELETE\"\n}\n"
},
"typeVersion": 3.4
},
{
"id": "6e369b93-0468-4cb3-8198-09bcd21a5b17",
"name": "POST",
"type": "n8n-nodes-base.set",
"position": [
-336,
816
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"method\": \"POST\"\n}\n"
},
"typeVersion": 3.4
},
{
"id": "cb22c4e7-1a77-455d-a4c8-d6be32d6136e",
"name": "GET",
"type": "n8n-nodes-base.set",
"position": [
-336,
672
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"method\": \"GET\"\n}\n"
},
"typeVersion": 3.4
},
{
"id": "42dcf978-3dbc-40bc-b514-a0fb5c01f5df",
"name": "Configuration des routes",
"type": "n8n-nodes-base.set",
"position": [
288,
672
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"routes\": [\n {\n \"action\": \"doSomething\",\n \"allowedMethods\": [\"GET\"],\n \"subflowId\": -1\n },\n {\n \"action\": \"doSomethingElse\",\n \"allowedMethods\": [\"GET\", \"POST\"],\n \"subflowId\": -1\n },\n {\n \"action\": \"deleteSomething\",\n \"allowedMethods\": [\"DELETE\"],\n \"subflowId\": -1\n }\n ]\n}\n"
},
"typeVersion": 3.4
},
{
"id": "91b1d0a9-431f-4806-b291-fd76973301d7",
"name": "Le paramètre de requête existe ?",
"type": "n8n-nodes-base.if",
"position": [
64,
672
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d010b9f7-91c1-45b8-8f57-0dd17c4db7d2",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Universal Receiver').item.json.query?.action }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "4a9798ab-c963-4e42-9a0b-8d8e9f2ac2ed",
"name": "Récepteur universel",
"type": "n8n-nodes-base.webhook",
"position": [
-544,
672
],
"webhookId": "a4696443-7af7-4183-8158-e2036fab13ef",
"parameters": {
"path": "universalReceiver",
"options": {},
"httpMethod": [
"GET",
"POST",
"DELETE",
"PATCH",
"PUT",
"HEAD"
],
"responseMode": "responseNode",
"multipleMethods": true
},
"typeVersion": 2.1
},
{
"id": "116a35d5-68cc-478c-8630-4f9a36bdba36",
"name": "Sticky : Détection de méthode",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
496
],
"parameters": {
"color": 7,
"width": 308,
"height": 152,
"content": "Method branches: Each branch hardcodes the HTTP method because n8n’s Webhook node does not expose the method as a property directly. We aggregate these branches so other nodes can reference a single `method` value."
},
"typeVersion": 1
},
{
"id": "1664cfd5-d8fb-4417-a99e-43e7ccf7568b",
"name": "Sticky : Configuration des routes",
"type": "n8n-nodes-base.stickyNote",
"position": [
208,
496
],
"parameters": {
"color": 7,
"width": 228,
"height": 152,
"content": "Route configuration: Map action names to subflow IDs and allowed HTTP methods. You can override this with other methods for receiving data, such as database queries or similar."
},
"typeVersion": 1
},
{
"id": "b95edefc-f4cf-4696-8d09-5271233f1d38",
"name": "Sticky : Résolveur",
"type": "n8n-nodes-base.stickyNote",
"position": [
464,
496
],
"parameters": {
"color": 7,
"width": 180,
"height": 152,
"content": "Resolve Route: Reads the query action and method, checks the config and decides whether to run a subflow. "
},
"typeVersion": 1
},
{
"id": "784a1ad8-d454-41fe-ab3b-801e81cce923",
"name": "Sticky : Exécuter et répondre",
"type": "n8n-nodes-base.stickyNote",
"position": [
880,
496
],
"parameters": {
"color": 7,
"width": 308,
"height": 152,
"content": "Execution & Response: Executes the target subflow when valid and returns its output."
},
"typeVersion": 1
},
{
"id": "c712a136-97f8-49fe-b01a-77ed001fe10f",
"name": "[Erreur] Paramètre de requête obligatoire manquant",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
288,
848
],
"parameters": {
"options": {
"responseCode": 400
},
"respondWith": "json",
"responseBody": "{\n \"error\": \"Required information not provided!\"\n}"
},
"typeVersion": 1.4
},
{
"id": "d10087c4-96d7-4df6-9918-81b95a95cd6c",
"name": "Résoudre",
"type": "n8n-nodes-base.code",
"position": [
496,
672
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// inputs\nconst method = $('Aggregate Method Branches').item.json.method;\nconst action = $(\"Universal Receiver\").item.json.query?.action;\nconst cfg = $(\"Routes Config\").item.json;\nconst routes = Array.isArray(cfg?.routes) ? cfg.routes : [];\nconst body = $(\"Universal Receiver\").item.json.query?.body || null;\n\n// Try to find a matching route (action + method)\nconst routeByAction = routes.find(r => String(r.action || '').toLowerCase() === String(action || '').toLowerCase());\nconst routeByActionAndMethod = routes.find(r => {\n const actionFound = String(r.action || '').toLowerCase() === String(action || '').toLowerCase();\n const methodAllowed = Array.isArray(r.allowedMethods) && r.allowedMethods.includes(method);\n return (actionFound && methodAllowed)\n});\n\nlet error = null;\nlet status = 200;\nlet allowHeader = null;\nlet workflowId = null;\n\nif (!action) {\n error = 'MISSING_ACTION';\n status = 400;\n} else if (!routeByAction) {\n error = 'ROUTE_NOT_FOUND';\n status = 404;\n} else if (!routeByActionAndMethod) {\n error = 'METHOD_NOT_ALLOWED';\n status = 405;\n allowHeader = Array.isArray(routeByAction.allowedMethods) ? routeByAction.allowedMethods.join(', ') : '';\n} else {\n workflowId = routeByActionAndMethod.subflowId ?? null;\n if (workflowId == null) {\n error = 'MISSING_SUBFLOW_ID';\n status = 500;\n }\n}\n\nreturn {\n action,\n method,\n error,\n status,\n allow: allowHeader,\n workflowIdToExecute: workflowId,\n body\n};"
},
"typeVersion": 2
},
{
"id": "80b31830-b665-4f01-a2d6-4a08779e3ebb",
"name": "La route est OK ?",
"type": "n8n-nodes-base.if",
"position": [
688,
672
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d010b9f7-91c1-45b8-8f57-0dd17c4db7d2",
"operator": {
"type": "number",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('Resolve').item.json.workflowIdToExecute }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "99fb75ed-9d41-4396-b4e6-ecead6e005d9",
"name": "Statut = 405 ?",
"type": "n8n-nodes-base.if",
"position": [
896,
992
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9928d071-7d13-4d05-9843-9f2f1b00b60e",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $('Resolve').item.json.status }}",
"rightValue": 405
}
]
}
},
"typeVersion": 2.2
},
{
"id": "c1882d8f-bfd1-482c-9f52-113c6111868f",
"name": "[Erreur] Méthode non autorisée",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1088,
992
],
"parameters": {
"options": {
"responseCode": 405,
"responseHeaders": {
"entries": [
{
"name": "Allow",
"value": "={{ $('Resolve').item.json.allow || '' }}"
}
]
}
},
"respondWith": "json",
"responseBody": "={\n \"error\": \"{{ $('Resolve').item.json.error }}\"\n}"
},
"typeVersion": 1
},
{
"id": "6325c215-2175-4703-8746-f18e5e8dd208",
"name": "Erreur - Non OK",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1088,
1168
],
"parameters": {
"options": {
"responseCode": "={{ $('Resolve').item.json.status || 400 }}"
},
"respondWith": "json",
"responseBody": "={ \"error\": \"{{ $('Resolve').item.json.error || 'Bad request' }}\" }"
},
"typeVersion": 1
},
{
"id": "b4f491b6-ea8b-470c-ad4b-d1c8922ae479",
"name": "Erreur - Sous-flux",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1088,
832
],
"parameters": {
"options": {
"responseCode": 500
},
"respondWith": "json",
"responseBody": "{\n \"error\": \"Unexpected error in the executed subflow!\"\n}"
},
"typeVersion": 1
},
{
"id": "2fe4296a-f97f-4dce-b49e-983a25720dd8",
"name": "Sticky : Détection de méthode 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1104,
496
],
"parameters": {
"color": 7,
"width": 500,
"height": 520,
"content": "This flow acts as a centralized API router using a single webhook URL to receive incoming HTTP requests with different methods (GET, POST, DELETE, PATCH, PUT, HEAD).\n\n- The flow separates and hardcodes each HTTP method into dedicated branches (Set nodes for GET, POST, etc.) since the webhook node doesn't expose the method directly. These branches are then consolidated in \"Aggregate Method Branches\" for easier reference.\n- It checks if the required query parameter action exists. If missing, it returns an error response.\n- The `Routes Config` node defines a list of routes mapping the action parameter and allowed HTTP methods to specific subflow IDs. This allows controlling which workflow to execute based on the request.\n- The `Resolve` code node matches the incoming action and method against the configured routes, returns error codes like 404 or 405 if no route/method matches, or identifies the subflow to execute.\n- Based on this result, the flow either executes the matched subflow or returns an appropriate error message and status code (400, 404, 405, 500).\n- After executing a subflow, it returns the subflow result as the response. If the subflow fails, a generic error is sent back.\n- This setup provides a flexible and maintainable way to route multiple API actions via a single webhook endpoint, with centralized management of routes, error handling, and response management."
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"cb22c4e7-1a77-455d-a4c8-d6be32d6136e": {
"main": [
[
{
"node": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"type": "main",
"index": 0
}
]
]
},
"3bdd165b-3ce6-4292-b696-bfc99a984ee3": {
"main": [
[
{
"node": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"type": "main",
"index": 0
}
]
]
},
"e6445f6f-1087-4e51-b8e5-ddb99456f868": {
"main": [
[
{
"node": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"type": "main",
"index": 0
}
]
]
},
"6e369b93-0468-4cb3-8198-09bcd21a5b17": {
"main": [
[
{
"node": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"type": "main",
"index": 0
}
]
]
},
"3aeaa1f4-9b71-46da-ae4f-277a356c1dc2": {
"main": [
[
{
"node": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"type": "main",
"index": 0
}
]
]
},
"56b8e967-39b4-43d4-b610-77e009227d07": {
"main": [
[
{
"node": "1659fc43-7139-49c8-a5a8-e1557dc89bae",
"type": "main",
"index": 0
}
]
]
},
"d10087c4-96d7-4df6-9918-81b95a95cd6c": {
"main": [
[
{
"node": "80b31830-b665-4f01-a2d6-4a08779e3ebb",
"type": "main",
"index": 0
}
]
]
},
"80b31830-b665-4f01-a2d6-4a08779e3ebb": {
"main": [
[
{
"node": "bb48dadb-e960-4e34-bb51-f0a0528c0369",
"type": "main",
"index": 0
}
],
[
{
"node": "99fb75ed-9d41-4396-b4e6-ecead6e005d9",
"type": "main",
"index": 0
}
]
]
},
"42dcf978-3dbc-40bc-b514-a0fb5c01f5df": {
"main": [
[
{
"node": "d10087c4-96d7-4df6-9918-81b95a95cd6c",
"type": "main",
"index": 0
}
]
]
},
"99fb75ed-9d41-4396-b4e6-ecead6e005d9": {
"main": [
[
{
"node": "c1882d8f-bfd1-482c-9f52-113c6111868f",
"type": "main",
"index": 0
}
],
[
{
"node": "6325c215-2175-4703-8746-f18e5e8dd208",
"type": "main",
"index": 0
}
]
]
},
"bb48dadb-e960-4e34-bb51-f0a0528c0369": {
"main": [
[
{
"node": "050ed363-ea07-4301-a53b-28c5c6328857",
"type": "main",
"index": 0
}
],
[
{
"node": "b4f491b6-ea8b-470c-ad4b-d1c8922ae479",
"type": "main",
"index": 0
}
]
]
},
"4a9798ab-c963-4e42-9a0b-8d8e9f2ac2ed": {
"main": [
[
{
"node": "cb22c4e7-1a77-455d-a4c8-d6be32d6136e",
"type": "main",
"index": 0
}
],
[
{
"node": "6e369b93-0468-4cb3-8198-09bcd21a5b17",
"type": "main",
"index": 0
}
],
[
{
"node": "56b8e967-39b4-43d4-b610-77e009227d07",
"type": "main",
"index": 0
}
],
[
{
"node": "3aeaa1f4-9b71-46da-ae4f-277a356c1dc2",
"type": "main",
"index": 0
}
],
[
{
"node": "3bdd165b-3ce6-4292-b696-bfc99a984ee3",
"type": "main",
"index": 0
}
],
[
{
"node": "e6445f6f-1087-4e51-b8e5-ddb99456f868",
"type": "main",
"index": 0
}
]
]
},
"91b1d0a9-431f-4806-b291-fd76973301d7": {
"main": [
[
{
"node": "42dcf978-3dbc-40bc-b514-a0fb5c01f5df",
"type": "main",
"index": 0
}
],
[
{
"node": "c712a136-97f8-49fe-b01a-77ed001fe10f",
"type": "main",
"index": 0
}
]
]
},
"1659fc43-7139-49c8-a5a8-e1557dc89bae": {
"main": [
[
{
"node": "91b1d0a9-431f-4806-b291-fd76973301d7",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Avancé - Création de contenu, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Sven Rösser
@svenPartager ce workflow