How to Call a Python Function in a Node.js App

Updated: December 28, 2023 By: Guest Contributor Post a comment

A few approaches to executing Python code in your Node.js project.

1. Using Child Process Module

Solution Description: This solution involves using the built-in child_process module in Node.js to spawn a Python process and execute a Python script. The Node.js app can then capture and use the output from the Python script.

  1. Create a Python script (script.py) with the desired functions.
  2. In your Node.js application, use the child_process module to call the Python script and capture its output.
  3. Parse the output in Node.js as needed.
const { spawn } = require('child_process');

const pythonProcess = spawn('python', ['script.py', arg1, arg2]);

pythonProcess.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

pythonProcess.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

pythonProcess.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

Pros:

  • Simple and does not require additional dependencies.
  • Can be used for one-time or low-frequency calls.

Cons:

  • Not suitable for high-performance applications due to the overhead of spawning new processes.
  • Data exchange is limited by string serialization.

2. Using a Socket-based Solution

Solution Description: In this approach, a Python script runs as a separate service, listening on a specific port. The Node.js app communicates with the Python service over sockets, sending and receiving messages.

  1. Set up a Python script that listens for network requests on a socket.
  2. In the Node.js app, establish a socket connection to the Python service to send and receive data.
  3. Implement a protocol for communication between the Node.js app and the Python script.
// Node.js side (client.js)
const net = require('net');
const client = new net.Socket();
client.connect(port, host, function() {
  console.log('Connected');
  client.write('Hello, server!');
});

client.on('data', function(data) {
  console.log('Received: ' + data);
  client.destroy(); // kill client after server's response
});

client.on('close', function() {
  console.log('Connection closed');
});

// Python side (server.py)
import socket

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((host, port))
serversocket.listen(5) # become a server socket

while True:
    clientsocket, address = serversocket.accept()
    data = clientsocket.recv(1024)
    clientsocket.send('Server response: ' + data)
    clientsocket.close()

Pros:

  • Allows for continuous and real-time communication between Node.js and Python.
  • Can be scaled to support multiple concurrent connections.

Cons:

  • More complex setup with additional handling of sockets and network programming.
  • Requires a network protocol between the services; may need to handle connection issues.

3. Using a Messaging Queue

Solution Description: A messaging queue such as RabbitMQ can be used for inter-process communication between a Node.js application and a Python script. This is suitable for distributed systems.

  1. Set up RabbitMQ and create a queue for messages.
  2. In the Node.js app, use a client library to send messages to the Python script via the queue.
  3. In the Python script, use a client library to receive messages from the queue and send back responses.
// Node.js side (sender.js)
const amqp = require('amqplib/callback_api');

amqp.connect('amqp://localhost', function(error0, connection) {
  if (error0) {
    throw error0;
  }
  connection.createChannel(function(error1, channel) {
    if (error1) {
      throw error1;
    }
    const queue = 'task_queue';
    const msg = 'Hello Python!';

    channel.sendToQueue(queue, Buffer.from(msg));
    console.log(" [x] Sent '%s'", msg);
  });
});

// Python side (receiver.py)
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.queue_declare(queue='task_queue')

def callback(ch, method, properties, body):
    print(f"Received {body}")

channel.basic_consume(queue='task_queue', on_message_callback=callback, auto_ack=True)

print('Waiting for messages. To exit press CTRL+C')
channel.start_consuming()

Pros:

  • Robust communication method suitable for distributed and scalable applications.
  • Offers reliable message delivery even when receiver is temporarily unavailable.

Cons:

  • Requires setting up and maintaining a messaging queue server.
  • Additional complexity with asynchronous communication patterns.

Conclusion

Calling a Python function from a Node.js application can be achieved through various means. The right approach depends on the application’s requirements, the frequency of calls, and the necessary performance. Whether using child processes for simple scripting, socket-based real-time communication, or a robust messaging queue for distributed systems, each method has its benefits and trade-offs. Developers should consider these factors along with their existing system architecture to select the most appropriate integration approach.