How to return file from webhook?

How can I return a file from a Javascript node through a webhook?

The file is returned (and previews) correctly from the Javascript node.

But attempting to return it from the Webhook response doesn’t return the file.

The file returned is 1KB and is the JSON object that contains the abbreviated base64 content.

We need to test this.
It seems like we should pass the content, not the entire file, depending on what you want to retrieve.

What file are you trying to retrieve?

The javascript node is generating a CSV file with the contents of a Latenode database table. The file preview from the javascript output message displays the file perfectly.

When tested returning the file content, it did not return the entire file and only the abbreviated base64 preview.

And is the goal to return a binary file for download?

Yes, navigating to the webhook should download the file.

After a brief series of tests, I managed to download files.

To begin with, I obtained a binary file using any node that provides file output.

Next, in the webhook response, I set the following headers:


Let Me Explain

  1. Set the correct content-type header based on the file type. For example, use application/csv for CSV files.

  2. Add the content-disposition header to specify that the response should be treated as a downloadable attachment and to provide a filename.

  3. Pass the binary file content directly in the body of the webhook.

Example Webhook Response Configuration

  • Body:

    {{$19.result.file.content}}
    
  • Headers:

    • Key: content-type
      Value: application/octet-stream or text/csv (if it’s a CSV file)

    • Key: content-disposition
      Value: attachment; filename="yourfilename.csv"


How This Works

  • content-disposition tells the browser or client that the response is a downloadable file.
  • filename specifies the name of the file when it’s downloaded.
  • content-type indicates the type of file being sent, ensuring it’s interpreted correctly.
1 Like

I created a separate thread for this — it might be useful to someone

Thanks, Raian! This worked perfectly. Here is my Javascript node, in case it is helpful for anyone else who needs to export the contents of the Latenode database collection to a CSV.

import { v4 as uuidv4 } from 'uuid';
import { Parser } from 'json2csv';
import fs from 'fs';

/** @CustomParams 
{
	"file_name": { 
		"type": "string", 
		"title": "File Name", 
		"description": "The name of the file to save the CSV data", 
		"required": false 
	},
	"database_id": {
		"type": "string",
		"title": "Database ID",
		"description": "The ID of the database to connect to",
		"required": true 
	},
	"collection_name": {
		"type": "string",
		"title": "Collection Name",
		"description": "The name of the collection to fetch data from",
		"required": true 
	}
}
*/
export default async function run({ execution_id, input, data, store, db }) {
	const getAllObjectKeys = (input) => {
		if (typeof input !== 'object' || input === null) {
			throw new Error('Input must be an object');
		}

		if (Array.isArray(input)) {
			throw new Error('Input must be an object, not an array');
		}

		const isSimpleObject = Object.values(input).every(value =>
			typeof value !== 'object' || value === null
		);

		if (isSimpleObject) {
			return [Object.keys(input)];
		}

		return Object.values(input).map(obj =>
			typeof obj === 'object' && obj !== null ? Object.keys(obj) : []
		);
	}

	const convertToCSV = (jsonData) => {
		const fields = getAllObjectKeys(jsonData[0].value);
		let columnHeaders = fields[0];

		const flattenedData = jsonData.map(record => record.value);

		const json2csvParser = new Parser({ fields: columnHeaders });

		try {
			const csv = json2csvParser.parse(flattenedData);
			return csv;
		} catch (err) {
			console.error('Error converting to CSV:', err.message);
			throw err;
		}
	}


	try {
		const fileName = data.file_name || `${uuidv4()}.csv`;

		const database_id = data.database_id;
		const collection_name = data.collection_name;

		const database = db.database(database_id);
		const collection = database.collection(collection_name);

		let allObjects = [];
		let objects;
		let offset = 0;
		const limit = 50;

		do {
			objects = await collection.findObjects(limit, offset);
			allObjects = allObjects.concat(objects);
			offset += limit;
		} while (objects.length === limit);

		const csv = convertToCSV(allObjects);

		fs.writeFileSync(fileName, csv);
		return {
			file: file(fileName)
		}
	} catch (error) {
		return {
			error: error.message
		};
	}
}
1 Like

Awesome! Thank You for sharing!

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.