Upload image url

System Information
  • Strapi Version: 3.3.3
  • Operating System: Windows 10
  • Database: Mongo DB
  • Node Version: 14
  • NPM Version: 6

I am working on a migration from our current CMS to Strapi.

Is there a way to post images to ‘/upload’ from an external URL? If not, what is the best way to post an image as a blob via XHR?

Thanks in advance,

You mean like this?

 const uploadByUrl = async () => {
    URL = "https://images.unsplash.com/photo-1611095785020-1ba3dd228ea7?ixid=MXwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60"; // <- image url
    fetch(URL)
      .then(response => response.blob())
      .then(function (myBlob) {
        const formData = new FormData();
        formData.append('files', myBlob);
        console.log(formData)
        fetch('http://localhost:1337/upload', {
          method: 'POST',
          headers: {
            "Authorization": "Bearer ", // <- Don't forget Authorization header if you are using it.
          },
          body: formData,
        }).then((response) => {
          const result = response.json()
          console.log("result", result)
        }).catch(function (err) {
          console.log("error:");
          console.log(err)
        });
      })
  }
  uploadByUrl()
1 Like

Hi,

this looks very promising!

I’m looking into a way to use this approach in the outdated strapi-plugin-import-content plugin that I’m trying to fix. I just don’t feel comfortable calling this method IN BULK, let’s say in batches of 50: this will download 50 images at once, create 50 FormData objects containing the binary data of these images and do 50 POST requests to the content-manager endpoints…

I’m also not sure how to get the authorization info in a server-side process to avoid allowing access to the image upload endpoint to the public. @kuwaitbinary Can you maybe share your vision on how to achieve this? See also Need help with reviving strapi-plugin-import-content for some more background info.

Thanks in advance!

As far as I know there is no update in bulk / updateMany yet according to this

I am still researching for createMany

The admin panel login for strapi is

// Login admin (POST http://localhost:1337/admin/login)
fetch("http://localhost:1337/admin/login", {
      "method": "POST",
      "headers": {
            "Content-Type": "application/json; charset=utf-8"
      },
      "body": "{\"email\":\"admin@example.com\",\"password\":\"pass\"}"
})
.then((res) => res.text())
.then(console.log.bind(console))
.catch(console.error.bind(console));

I assume you know the regular login method

169.254.37.16:1337/auth/local

Maybe later on I will try to re-visit the link you posted and think of idea how to use the plugin to upload many images. @4levels

Hi @kuwaitbinary,

thanks for the mention! I think I found a possible root cause for both the async image import and the upload from url feature not working. It seems the Strapi upload service, allthough documented to handle both files and Buffers, can only handle files since it expects a path attribute to exist on the uploaded file.
When working with Buffers however, there is no file path as the file is not created and only exists as Buffer in memory. By simply adding a check if the path attribute exists, I could work around this and effectively upload images to the media library, even without user info (as long as I make the media / upload endpoint publicly accessible).

I’ve created a fork from the Strapin repo, please see the diff here: Comparing strapi:master...4levels:master · strapi/strapi · GitHub

I’m currently testing my suspicions, I’ll keep you posted here as well.

Kind regards,

Erik aka 4levels

Hi,

sadly enough the change above DOES NOT fix the Media library “from URL” feature.
I’m still working on my own version of the import-content plugin, published here: GitHub - kiddicolour/strapi-plugin-import-content as all I have left to do is fix a weird bug.

When sending the related file data to the upload service, it somehow is not handled correctly. The upload_file_morph record is correctly created in the database, but somehow it references the url of the file instead of the id, allthough passed in correctly as numeric value. As soon as I manually adjust the value in the database to point to an actual id instead of the string url, the media is correctly linked and displayed. I also want to add a content type override option, as the images that I need to import are hosted on an old wordpress server that doesn’t pass the correct Content-Type (each png images gets Content-Type “text/html”. Other servers I’ve tested with, send the correct mimetype…

Hi,

I posted a topic related with this. Have you solved it since then?

Has anyone successfuly implemented this? Trying to get it done in v4, to seed my strapi db from another CMS, with no luck so far. I had an implementation for v3 where I downloaded the files to my fs then uploaded them and it worked, would be nice to skip the writting to system part… :slight_smile:

Here is my blob implementation, heavily inspired from above. after raising the file size limits in the middleware.js file. I’m still getting a 400 error “files are empty”

async function uploadByUrl(imageurl) {
  try {
    console.log("hello", imageurl);
    const image = await fetch(imageurl);
    const imagetoUpload = await image.blob();
    console.log(imagetoUpload.type);
    const arrayBuffer = await imagetoUpload.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);

    const formData = new FormData();
    formData.append("files", buffer);

    const uploadedBlobToStrapi = await fetch(
      "http://localhost:1337/api/upload",
      {
        method: "POST",
        headers: {
          authorization: `Bearer ${STRAPI_TOKEN}`,
        },
        body: formData,
      }
    );
    const results = await uploadedBlobToStrapi.json();
    return results;
  } catch (error) {
    console.log(error.message);
  }
}

Hello!

After a bit of trial and error, I got this working in V4! My use case is that I fetch the profile image of users who authenticate via third party provider, and then upload that image to my Strapi / S3 bucket.

Here is my implementation. I’m using a beforeCreate lifecycle function in src/extensions/users-permissions/content-types/user/lifecycles.js

module.exports = {
    beforeCreate(event) {

        const axios = require("axios");
        const FormData = require('form-data');

        if (event.params.provider !== "local") {
            try {
                const img = event.params.data.profile_picture_social; // url

                async function fetchAndUploadSocialImage(img) {
                    const response = await axios.get(img, {responseType: "arraybuffer"});

                    const form = new FormData();
                    form.append("files", response.data, `useravatar-${event.params.data.username}.jpg`)
                    
                    const upload = await axios.post(`${process.env.API_URL}/api/upload`, form).catch((error)=> {
                        console.log(error.response.data.error)
                    })
                }
                fetchAndUploadSocialImage(img);
            } catch (error) {
                console.log(error)
            }
        }
    },
}

did you fix the issue?, i am also getting the same error