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

5 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 }

};
1 Like

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)

3 Likes

This is an excellent extension - I’m about to start using this but before I start, is it compatible with AC2…?

1 Like

As it is a server connect extension the app connect version should be irrelevant. (famous last words!)

1 Like

This extension seems to work well with image downloads but there seems to be an issue with urls with parameters which you would need for the api call for qr codes.

Looking to see if I can modify code.

1 Like

thank you Brian, I seem to always struggle with dynamic parameters in Urls, it keeps me awake at night :slight_smile:

The component seems to work as it should, downloading the image of the QR code BUT the image is incorrectly named.

i tried:
image

url being:

https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=https:wappler.io

produces a file called qr.io

Renaming to qr.png reveals the file is correct, just the file extension is wrong

qr

(scans to link to wappler website)

Guess a rename file step could get around that

1 Like

This looks excellent Brian, thank you for your work :slight_smile:

@TMR , made an update to this custom extension.

Added a new input “Force Extension” which, as the name suggests, forces the file download extension to the input value. For force extension to work a custom filename must also be specified.

Default functionality remains unchanged.

image

Hope that is of use, any issues let me know

FileDownloadModule.zip (1.7 KB)

2 Likes

Ahhh Brian that’s totally excellent, thank you :slight_smile:

As this is a manual install I’m trying to find my extensions folder but cant find it, can you point me in the right direction please?

yes, you have to manually create it

you will need a folder called /extensions/server_connect/modules

image

Just to warn, have not tested in Production environment yet

1 Like

As this is manual install you may need to manually add the npms manually

it is dependent on axios npm.

It does appear in package.json so should be installed automatically by node (fingers crossed)

1 Like

Got it all sorted now Brian, many thanks :slight_smile:

That’s not problem Brian, it’ll be tested well before its deployed, I’ll keep you posted if there are any issues.

1 Like

thanks for that Brian, I’d have missed this one - I checked and its there so no worries.

Great job working on this extension! (I was on a camping trip :sunglasses: ) @Hyperbytes, do you mind if I use your file in the original post? It seems like an improved version of the extension.

Have npm version available now, will be releasing a tutorial today so maybe best to cross link to that when released. For the moment the npm is here.

2 Likes