Get File from API Action - NodeJS [OpenSource] (v0.4)

Hi there fellow Wapplers,

I have created my first extension :tada:
Well…not really. I have only copied @mebeingken’s extension:
Custom File Actions [Node]

And adjusted it to suit my needs. Also learned a lot from this extension by @sid:
API File Upload Action - NodeJS & PHP [Open Source]

I did see quite a lot of topics requesting something like this, so I thought it would be good to share it.

You find the action next to Sid’s:
action

And currently these are the settings available:

It now downloads a file from an api and saves it under the original filename to your desired save path.

Like I said, it is based on Ken’s extension, which was based on node request. Which is deprecated, I am not sure if this is an issue or not. If it is an issue please suggest alternatives.

Right now I only made an option to change the url and add headers to the request. Because that is what I needed. If you need params or body or something, please comment below.

Also, right now it does not catch errors or response codes. I haven’t figured out how to properly do that, yet.

FileDownloadModule.zip (1.8 KB)

bg

Jelle

4 Likes

I actually did run into issues with the request library a while back. I can’t recall the specifics, but it was obviously time to move on from that library.

Here is a version of the action that now uses Axios:

exports.write_binary = async function (options) {
    //retrieves a file via remote http request and saves the file to the local server
    //names the file using a uuid

    //for converting file paths provided in UI
    const { toSystemPath } = require('../../../lib/core/path');

    //uuid package
    const { v4: uuidv4 } = require('uuid');

    //required for retrieving 
    const axios = require('axios')

    //and saving file
    const fs = require('fs-extra');

    //convert the user local_path provided in the API action to useable in the module
    let path = toSystemPath(this.parseRequired(this.parse(options.local_path), 'string', 'fs.exists: path is required.'));

    //evaluate the data binding for remoteURL
    let remoteURL = this.parseRequired(options.file_url, 'string', 'parameter file_url is required.');

    //generate uuid
    let uuid = uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'

    //set the filename
    let file_name = path + '/' + uuid;


    async function downloadImage() {
        const url = remoteURL;

        const writer = fs.createWriteStream(file_name)

        const response = await axios({
            url,
            method: 'GET',
            responseType: 'stream'
        })

        response.data.pipe(writer)

        return new Promise((resolve, reject) => {
            writer.on('finish', resolve)
            writer.on('error', reject)
        })
    };

    await downloadImage();

    //return the file_name
    return { "file_name": uuid }

};

HI Jelle,

Just playing with your extension as a test and to learn more but having a problem with the URL field.

If I use a static url (like your screenshot) the file is downloaded from the given url but if I use a dynamic variable (e.g. the response from an API with the url of the file the action fails - “Error: parameter value is required.”

This is the error detailed in the js for the URL field.

I had assumed I could use a variable/dynamic value (which is a string of a valid url) given there is a data binding icon:

Do you use it this way?

Are there any special steps I need to take first?

Thanks in advance for any pointers you can provide :slight_smile:

Paul

Hi Paul,

I haven’t looked into this extension for a while, but I expect to be needing it in the coming weeks. I will report back with my findings and fixes, if needed.

1 Like

Hi Jelle,

I have done a little more work on this today and found, as usual, the issue was with my implementation :frowning:

The dynamic value I was retrieving from my API call “favicon.data[0].$value” which was provided by the Wappler data binding selection was not actually giving me a value, it should have been “favicon.data[0]”

It now works and my day of trying to find an error has taught me loads about extensions :slight_smile:

Thanks, Paul.

1 Like

Here is an updated version that uses axios, like @mebeingken suggested.
Also an option to provide a custom filename, since some API’s do not return desirable filenames.
GetFileFromAPIV04.zip (1.7 KB)

2 Likes