Appeler un Script Python depuis n8n
Mise à jour (Mars 2026) : Depuis la publication de cet article, j'utilise Claude Code + n8n-MCP pour construire et déboguer les workflows n8n directement depuis le terminal. Cette combinaison rend l'approche FastAPI ci-dessous encore plus puissante : Claude Code échafaude le workflow, n8n l'exécute, Python gère les tâches lourdes. J'ai détaillé toute la configuration ici.
Parfois, il faut appeler un script Python depuis un workflow n8n. Et là, c'est le drame. Certes, n8n propose un nœud Code qui prend en charge Python, mais son implémentation est limitée. Si vous voulez exploiter toute la puissance de Python — bibliothèques externes, calculs complexes, modèles de machine learning — il vous faut un environnement Python dédié.
TL;DR : Utilisez FastAPI pour encapsuler vos scripts Python en endpoints API, conteneurisez avec Docker, et appelez depuis vos workflows n8n via des requêtes HTTP. Cela contourne les limitations du nœud Code Python de n8n pour accéder à toutes les capacités Python, bibliothèques externes incluses.
Dans ce guide, je vais vous montrer comment intégrer un script Python dans un workflow n8n en utilisant FastAPI pour créer un endpoint API. Que vous souhaitiez traiter des images, manipuler des données, ou effectuer n'importe quelle tâche personnalisée, cette approche vous permet d'exploiter la puissance de Python au sein des capacités d'automatisation de n8n.
Nous couvrirons :
- L'encapsulation d'un script Python dans une application FastAPI.
- Sa conteneurisation avec Docker.
- Son appel depuis un workflow n8n.
À la fin, vous aurez une configuration fonctionnelle où n8n déclenche votre script Python via une requête HTTP.
Prérequis
Avant de commencer, assurez-vous d'avoir :
- Docker installé sur votre machine ou serveur.
- n8n en cours d'exécution (de préférence dans Docker, bien que d'autres configurations fonctionnent aussi).
- Une familiarité de base avec Python, Docker, et les workflows n8n.
- Un pot de baume du tigre pour booster le courage.
Étape 1 : Créer votre script Python
Commençons par un script Python simple. Pour cet exemple, nous utiliserons un script de redimensionnement d'image, mais vous pouvez le remplacer par n'importe quelle logique Python dont vous avez besoin.
Script d'exemple : resize.py
Ce script redimensionne une image en carré de 1000x1000 tout en conservant ses proportions et en ajoutant un arrière-plan blanc.
J'ai choisi cet exemple parce que le nœud de redimensionnement d'image dans n8n ne fonctionne pas correctement en ce moment. Les gars de n8n 😵💫, vous devez corriger ça !
from PIL import Image
import argparse
def resize_image(input_path, output_path, size=1000):
# Open the original image
original_image = Image.open(input_path)
width, height = original_image.size
# Calculate new dimensions while preserving aspect ratio
ratio = min(size / width, size / height)
new_width = int(width * ratio)
new_height = int(height * ratio)
# Resize the image
resized_image = original_image.resize((new_width, new_height), Image.LANCZOS)
# Create a white 1000x1000 background and paste the resized image
final_image = Image.new("RGB", (size, size), (255, 255, 255))
offset_x = (size - new_width) // 2
offset_y = (size - new_height) // 2
final_image.paste(resized_image, (offset_x, offset_y))
# Save the result
final_image.save(output_path)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Resize image to 1000x1000")
parser.add_argument("input_image", help="Path to input image")
parser.add_argument("output_image", help="Path to output image")
args = parser.parse_args()
resize_image(args.input_image, args.output_image)
Sauvegardez ceci sous resize.py. Il prend un chemin d'image d'entrée et un chemin de sortie comme arguments.
Étape 2 : Créer un wrapper FastAPI
Au lieu de simplement construire une application FastAPI, nous encapsulons en fait notre script Python avec une API, le rendant accessible à n8n. Ce wrapper permettra à n8n d'interagir avec le script via des requêtes HTTP, garantissant une meilleure flexibilité et évolutivité.
💡 Une autre option aurait été d'utiliser Flask, qui est un framework léger populaire pour construire des API. Cependant, nous avons choisi FastAPI car il offre un support asynchrone, une validation automatique des données, et une documentation OpenAPI intégrée, le rendant plus rapide et plus efficace pour gérer les requêtes API — surtout dans des scénarios d'automatisation comme n8n.
L'un des principaux avantages de FastAPI est la facilité avec laquelle on peut l'étendre. Ajouter plus de scripts est aussi simple que de définir de nouveaux endpoints. Par exemple, si vous avez besoin d'un autre script pour appliquer un filtre en niveaux de gris à une image, vous pouvez simplement créer une nouvelle route comme /grayscale et appeler le script correspondant. Cette approche modulaire facilite la montée en charge de votre API et l'intégration de plusieurs scripts Python dans votre workflow n8n sans modifier les endpoints existants.
## app.py
from fastapi import FastAPI, UploadFile, File
from fastapi.responses import StreamingResponse
import subprocess
import tempfile
import os
import io
app = FastAPI()
@app.post("/resize")
async def resize_image(file: UploadFile = File(...)):
# Create temporary files for input and output
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as input_file:
input_path = input_file.name
input_file.write(await file.read())
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as output_file:
output_path = output_file.name
# Run the resize script
try:
subprocess.run(["python", "resize.py", input_path, output_path], check=True)
except subprocess.CalledProcessError as e:
return {"error": f"Failed to resize image: {e}"}
# Read the resized image
with open(output_path, "rb") as f:
image_data = f.read()
# Clean up temporary files
os.remove(input_path)
os.remove(output_path)
# Return the image as a response
return StreamingResponse(io.BytesIO(image_data), media_type="image/jpeg")
Comment ça fonctionne :
- L'endpoint /resize accepte un fichier uploadé.
- Il sauvegarde le fichier temporairement, appelle resize.py en utilisant subprocess, et retourne l'image redimensionnée.
- Les fichiers temporaires sont supprimés après traitement pour éviter l'encombrement.
Sauvegardez ceci sous app.py dans le même répertoire que resize.py.
Note : Réflexion sur l'approche FastAPI avec subprocess vs classe Python 🥊
Jazys m'a fait remarquer : "Bon, pour un développeur, ce genre de ligne pique les yeux. Le mieux serait de créer une classe Python et d'appeler cette classe. De toute façon, quand tu voudras ajouter de nouvelles API un jour, tu devras modifier ton app.py, alors autant intégrer Python jusqu'au bout."
Il a absolument raison d'un point de vue puriste : utiliser une classe Python (comme ImageProcessor) pour encapsuler la logique, intégrée directement dans l'application FastAPI, améliore la robustesse, les performances et la maintenabilité, surtout pour une application évolutive avec de nouvelles routes. Pour un développeur cherchant une solution propre, modulaire et bien documentée (avec documentation Swagger automatique), cette approche est idéale (par ex., importer une classe dans app.py avec des méthodes réutilisables).
Cependant, en tant que bricoleur pragmatique et non-développeur, je préfère ma solution subprocess : elle me permet d'appeler rapidement des petits scripts indépendants sans me soucier de robustesse ou d'évolutivité, ce qui convient à mes besoins simples. Merci pour cette remarque pertinente, Jazys — ta sagesse de dev transpire ! 😉
Étape 3 : Définir les dépendances
Créez un fichier requirements.txt pour lister les packages Python dont nous avons besoin (au fait, si vous êtes aussi paresseux que moi, vous pouvez générer un fichier requirements.txt automatiquement en exécutant la commande suivante dans votre répertoire de projet : pip freeze > requirements.txt)
## requirements.txt
fastapi
uvicorn
pillow
python-multipart
Sauvegardez ceci sous requirements.txt.
Étape 4 : Conteneuriser avec Docker
Pour assurer une intégration transparente avec n8n et maintenir la cohérence entre les environnements, nous allons conteneuriser notre application FastAPI en utilisant Docker. Puisque n8n fonctionne probablement dans un conteneur Docker, nous connecterons notre API Python au même réseau Docker dès le départ.
De plus, nous explorerons deux approches : utiliser un Dockerfile autonome ou exploiter docker compose pour des configurations plus complexes. Dans des cas spécifiques, comme lors du traitement d'un grand nombre de fichiers, nous discuterons aussi de l'utilisation d'un volume partagé.
Configuration du réseau
n8n et notre API Python doivent communiquer au sein du même réseau Docker. D'abord, identifiez le réseau que votre conteneur n8n utilise :
docker inspect <n8n_container_name> | grep Network
Remplacez <n8n_container_name> par le nom de votre conteneur n8n (par ex., n8n-akc0oo0ogc0gkog0g8ww). Cherchez la section NetworkID ou Networks pour trouver le nom du réseau (par ex., coolify ou n8n_default). Nous utiliserons ce réseau pour nous assurer que les conteneurs peuvent communiquer entre eux en utilisant leurs noms de conteneur.
Remarque : Nous aurions pu choisir d'exposer nos scripts Python à internet en mappant un port public (par ex., -p 8000:8000) et en le sécurisant avec HTTPS et authentification. Cependant, dans ce cas, nous avons opté pour les garder internes au VPS. Cela simplifie la configuration et évite les complexités de sécurité qui surviennent quand les services sont exposés au monde, comme gérer les pare-feu, certificats, reverse proxy, ou les attaques potentielles.
Option 1 : Utiliser un Dockerfile autonome
C'est l'approche la plus simple, idéale pour une configuration à service unique.
Créez un Dockerfile dans votre répertoire de projet :
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
COPY resize.py .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Construisez l'image Docker :
docker build -t fastapi-python-app .
Exécuter le conteneur
Exécutez le conteneur, en le connectant au réseau n8n (remplacez <n8n_network> par le nom réel du réseau) :
docker run -d --name python-api --network <n8n_network> fastapi-python-app
-name python-api : Nomme le conteneur pour une référence facile.
-network <n8n_network> : Le connecte au réseau de n8n, permettant la communication via http://python-api:8000.
L'API sera accessible à http://python-api:8000/resize au sein du réseau.
Cas spécifique : Volume partagé
Si votre workflow implique le traitement d'un grand nombre de fichiers (par ex., redimensionner des centaines d'images), vous pourriez vouloir éviter de transférer répétitivement des fichiers via HTTP. Au lieu de cela, vous pouvez utiliser un volume Docker partagé pour stocker des fichiers accessibles à la fois à n8n et à l'API Python. Par exemple :
docker run -d --name python-api --network <n8n_network> -v /path/to/shared/folder:/data fastapi-python-app
- -v /path/to/shared/folder:/data : Monte un répertoire de l'hôte (/path/to/shared/folder) vers /data dans le conteneur.
- Mettez à jour app.py pour lire/écrire des fichiers depuis /data au lieu d'utiliser des fichiers temporaires, et assurez-vous que n8n peut écrire dans le même volume. C'est une exception plutôt que la norme, car cela couple les conteneurs plus étroitement, mais c'est efficace pour les opérations de fichiers en masse.
Option 2 : Utiliser Docker Compose
Pour une configuration plus structurée, surtout si vous gérez plusieurs services ou voulez définir le réseau explicitement, utilisez docker-compose.
Créez un fichier docker-compose.yml :
services:
python-api:
build: .
image: fastapi-python-app
container_name: python-api
command: uvicorn app:app --host 0.0.0.0 --port 8000
networks:
- n8n_network
networks:
n8n_network:
name: <n8n_network>
external: true
- build: . : Construit l'image depuis le Dockerfile dans le répertoire courant.
- networks : Connecte le service au réseau n8n existant (remplacez <n8n_network> par le nom réel de docker network ls).
Construire et exécuter
Démarrez le service :
docker compose up -d
Cela lance le conteneur python-api dans le réseau spécifié.
Volume partagé avec Docker Compose
Pour les scénarios avec de nombreux fichiers, ajoutez un volume à docker-compose.yml :
services:
python-api:
build: .
image: fastapi-python-app
container_name: python-api
command: uvicorn app:app --host 0.0.0.0 --port 8000
volumes:
- shared-data:/data
networks:
- n8n_network
volumes:
shared-data:
networks:
n8n_network:
name: <n8n_network>
external: true
- volumes : Définit un volume nommé (shared-data) monté à /data dans le conteneur.
- Si n8n est aussi géré par ce docker-compose.yml, ajoutez-le comme service et attachez-le au même volume et réseau. Sinon, assurez-vous que le conteneur de n8n monte le même volume séparément.
Gestion avec Docker Compose
Arrêtez ou redémarrez avec :
docker compose down
docker compose up -d
Étape 5 : Vérifier et tester le conteneur
Avant d'intégrer l'API Python avec n8n, confirmons que le conteneur fonctionne correctement et que l'API répond comme attendu. Nous allons le tester avec curl d'une manière que vous pourrez ensuite copier-coller directement dans le nœud HTTP Request de n8n pour une transition transparente.
Vérifier le statut du conteneur
Confirmez que le conteneur fonctionne :
docker ps
Cherchez python-api dans la liste avec un statut Up et aucun port exposé (puisque nous utilisons un réseau interne). S'il ne fonctionne pas, vérifiez les logs :
docker logs python-api
Corrigez toute erreur (par ex., fichiers manquants, problèmes de dépendances) en reconstruisant l'image si nécessaire :
docker build -t fastapi-python-app .
docker run -d --name python-api --network <n8n_network> fastapi-python-app
Tester l'API localement
Testez l'endpoint depuis le réseau Docker en utilisant curl :
docker run --rm --network <n8n_network> curlimages/curl curl -X POST -F "file=@/path/to/test.jpg" http://python-api:8000/resize -o output.jpg
- Remplacez /path/to/test.jpg par un chemin d'image de test, en le montant si nécessaire (par ex., -v /local/path:/data et utilisez file=@/data/test.jpg).
- Vérifiez qu'output.jpg contient l'image redimensionnée.
Bonus : Commande curl compatible n8n
Voici une commande curl que vous pouvez exécuter directement sur votre hôte (si le port est exposé) ou adapter pour n8n :
curl -X POST -F "file=@/path/to/test.jpg" http://python-api:8000/resize -o output.jpg
- Pourquoi c'est utile : Cette commande exacte peut être copiée dans le nœud HTTP Request de n8n via l'option import cURL et en la collant dans le champ "Raw Request" (après avoir ajusté le chemin du fichier pour correspondre aux données binaires de n8n). C'est un moyen rapide de prototyper la requête avant de l'affiner dans n8n.
- Si vous avez exposé le port localement (par ex., avec -p 8000:8000), exécutez ceci depuis votre VPS pour tester en dehors de Docker.
Si cela fonctionne, l'API est prête pour que n8n l'appelle 😀.
Étape 6 : Configurer n8n pour appeler l'API
Dans votre instance n8n :
- Ouvrez l'éditeur de workflow.
- Ajoutez un nœud HTTP Request.
- Configurez-le comme ceci :

- URL : http://python-api:8000/resize (en utilisant le nom du conteneur comme nom d'hôte).
- Method : POST.
- Send Binary Data : Activez cette option.
- Binary Property : Définissez à data (ou le nom de votre champ d'entrée binaire).
Ajouter un fichier image
Si vous redimensionnez une image depuis le disque :
- Ajoutez un nœud Read Binary File avant le nœud HTTP Request.
- Définissez le chemin du fichier vers votre image d'entrée.
- Connectez-le au nœud HTTP Request, en vous assurant que les données binaires transitent.

Si ce contenu vous est utile, vos applaudissements 👏, surlignages 🖍️, ou commentaires 💬 nous aident à produire plus de matériel pertinent.
Étape 7 : Tester le workflow
- Exécutez le workflow n8n.
- Vérifiez la sortie du nœud HTTP Request : Vous devriez voir l'image redimensionnée retournée comme données binaires.
- Admirez ce chef-d'œuvre ! 😆🔥
Dépannage
- "Connection refused" : Assurez-vous que les deux conteneurs sont sur le même réseau Docker et que l'URL correspond au nom du conteneur (python-api).
- "Module not found" : Vérifiez requirements.txt et reconstruisez l'image Docker.
- Problèmes de fichiers : Si n8n ne trouve pas le fichier d'entrée, vérifiez que le chemin est accessible dans son conteneur.
Vous voilà parés !
Vous êtes maintenant capable d'appeler en toute sécurité des scripts Python depuis n8n sans aucun effet de bord sur votre environnement d'automatisation. En plus, vous pourriez même utiliser ces scripts en dehors de n8n — mais ça, c'est une toute autre histoire !
Bonne automatisation ! Faites-moi savoir dans les commentaires si vous rencontrez des problèmes ou avez des questions. 🚀
J'ai documenté la structure CLI, le CLAUDE.md de production, et les contraintes d'agent que j'utilise dans tous mes projets d'automatisation dans un kit gratuit. 3 fichiers, 10 minutes.
Transformer n8n et Python en duo d'automatisation puissant : découvrez comment débloquer des workflows complexes avec FastAPI et Docker.