Does aem-upload work with external assets and not local files? | Community
Skip to main content
sarav_prakash
Community Advisor
Community Advisor
August 9, 2024
Solved

Does aem-upload work with external assets and not local files?

  • August 9, 2024
  • 2 replies
  • 861 views

I am trying to use https://github.com/adobe/aem-upload for my project. I was able to test separately from local by keeping as asset in local folder and uploading successfully into cloud aem. But next level, I am trying to pass url instead of local files and run from AppBuilder action. 

 

I realize, this is working only with local files. When I try like 

const targetUrl = 'http://localhost:4502/content/dam/target'; // list of all local files that will be uploaded. const uploadFiles = [ { fileName: 'file1.jpg', // name of the file as it will appear in AEM fileSize: 1024, // total size, in bytes, of the file filePath: 'https://www.google.com/publicurl/file1.jpg' }, { fileName: 'file2.jpg', fileSize: 512, filePath: 'https://www.google.com/publicurl/file2.jpg' } ]; const upload = new DirectBinary.DirectBinaryUpload(); const options = new DirectBinary.DirectBinaryUploadOptions() .withUrl(targetUrl) .withUploadFiles(uploadFiles);

pass an absolute url to filePath, this is not working. 

 

Next documentation reads to use local files, OR download the asset as blob and ignore filePath. Is there a working example where you download asset into blob and call withUploadFiles() ?

 

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by sarav_prakash

After multiple attempts, learning aem-upload CANNOT be used from nodejs backend. It works only for uploading from local files. OR have to build a frontend application and can upload <input type=file> values. But when I had an external (dropbox) url, I am not able to directly call aem-upload. 

withUploadFiles() does support a `blob` type. But accepts <input type=file> value. Now nodejs provides hacky ways to simulate browser input. But I tried different ways and simply didnt work.

 

Instead I was able to directly call Asset Compute microservices. 

 

This is the fix that works from nodejs.

 

import axios from "axios"; import { base64Credentials, BASIC_AUTH_HEADER } from "./common.mjs"; import { Core } from "@adobe/aio-sdk"; import { Buffer } from "node:buffer"; const makeUploadRequest = async ( initiateUploadResponse, sourceUrl, fileName, logger ) => { const responseJson = JSON.parse(initiateUploadResponse); const arrayNode = responseJson.files; if (!arrayNode || arrayNode.length === 0) { throw new Error("No file information found in the response"); } const uploadToken = arrayNode[0].uploadToken; const mimeType = arrayNode[0].mimeType; const binaryPUTUrl = arrayNode[0].uploadURIs[0]; axios .get(sourceUrl, { responseType: "arraybuffer" }) .then((response) => { const fileBytes = Buffer.from(response.data); return axios.put(binaryPUTUrl, fileBytes, { headers: { "Content-Type": "application/octet-stream", }, }); }) .then((putResponse) => { logger.log("Put response status:", putResponse.status); // Handle the putResponse as needed }) .catch((error) => { logger.error("An error occurred:", error); }); makeCompleteUploadRequest(uploadToken, mimeType, fileName, logger); }; const makeCompleteUploadRequest = (uploadToken, mimeType, fileName, logger) => { try { const form = new FormData(); form.append("uploadToken", uploadToken); form.append("fileName", fileName); form.append("createVersion", "true"); form.append("versionLabel", fileName); form.append("mimeType", mimeType); axios .post( "https://author-**-**.adobeaemcloud.com/content/dam/product-content.completeUpload.json", form, { headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", Authorization: `Basic ${base64Credentials}`, }, } ); } catch (error) { logger.error("Error completing upload:", error); throw error; } }; const initiateUpload = async (asset, logger) => { const data = new FormData(); data.append("fileName", asset.fileName); data.append("fileSize", asset.fileSize); const config = { method: "post", url:"https://author-**-**.adobeaemcloud.com/content/dam/product-content.initiateUpload.json", headers: BASIC_AUTH_HEADER, data: data, }; try { const initiateUpload = await axios.request(config); logger.log(`successfully initiated ${initiateUpload}`); makeUploadRequest(initiateUpload, asset.sourceUrl, asset.fileName, logger) } catch (err) { logger.error(`error in uploading assets ${JSON.stringify(err)}`); } }; export const uploadAsset = (assets) => { const logger = Core.Logger("main"); assets.forEach((asset) => { initiateUpload(asset, logger); }); };

 

2 replies

EstebanBustamante
Community Advisor and Adobe Champion
Community Advisor and Adobe Champion
August 9, 2024

Hi, 

You can pass assets through a REST call if that's what you are asking, you need to get the "asset" from your request body and build the uploadFiles array with it, that's it.  Something like this would work:

 

// req = request // file = is the actual asset passed through a POST call in this case let assetToUpload = { "fileName": req.file.originalname, "fileSize": req.file.size, "versionLabel": "original", "blob": req.file.buffer, "replace": true }; let uploadFiles = []; uploadFiles.push(assetToUpload); const options = new DirectBinary.DirectBinaryUploadOptions() .withUrl("yourAEMtargetInstance") .withUploadFiles(uploadFiles) .withHttpOptions({ headers: { Authorization: `Bearer ${ACCESS_TOKEN}` } });

Hope this helps.

 

 

 

Esteban Bustamante
sarav_prakash
Community Advisor
sarav_prakashCommunity AdvisorAuthorAccepted solution
Community Advisor
August 15, 2024

After multiple attempts, learning aem-upload CANNOT be used from nodejs backend. It works only for uploading from local files. OR have to build a frontend application and can upload <input type=file> values. But when I had an external (dropbox) url, I am not able to directly call aem-upload. 

withUploadFiles() does support a `blob` type. But accepts <input type=file> value. Now nodejs provides hacky ways to simulate browser input. But I tried different ways and simply didnt work.

 

Instead I was able to directly call Asset Compute microservices. 

 

This is the fix that works from nodejs.

 

import axios from "axios"; import { base64Credentials, BASIC_AUTH_HEADER } from "./common.mjs"; import { Core } from "@adobe/aio-sdk"; import { Buffer } from "node:buffer"; const makeUploadRequest = async ( initiateUploadResponse, sourceUrl, fileName, logger ) => { const responseJson = JSON.parse(initiateUploadResponse); const arrayNode = responseJson.files; if (!arrayNode || arrayNode.length === 0) { throw new Error("No file information found in the response"); } const uploadToken = arrayNode[0].uploadToken; const mimeType = arrayNode[0].mimeType; const binaryPUTUrl = arrayNode[0].uploadURIs[0]; axios .get(sourceUrl, { responseType: "arraybuffer" }) .then((response) => { const fileBytes = Buffer.from(response.data); return axios.put(binaryPUTUrl, fileBytes, { headers: { "Content-Type": "application/octet-stream", }, }); }) .then((putResponse) => { logger.log("Put response status:", putResponse.status); // Handle the putResponse as needed }) .catch((error) => { logger.error("An error occurred:", error); }); makeCompleteUploadRequest(uploadToken, mimeType, fileName, logger); }; const makeCompleteUploadRequest = (uploadToken, mimeType, fileName, logger) => { try { const form = new FormData(); form.append("uploadToken", uploadToken); form.append("fileName", fileName); form.append("createVersion", "true"); form.append("versionLabel", fileName); form.append("mimeType", mimeType); axios .post( "https://author-**-**.adobeaemcloud.com/content/dam/product-content.completeUpload.json", form, { headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", Authorization: `Basic ${base64Credentials}`, }, } ); } catch (error) { logger.error("Error completing upload:", error); throw error; } }; const initiateUpload = async (asset, logger) => { const data = new FormData(); data.append("fileName", asset.fileName); data.append("fileSize", asset.fileSize); const config = { method: "post", url:"https://author-**-**.adobeaemcloud.com/content/dam/product-content.initiateUpload.json", headers: BASIC_AUTH_HEADER, data: data, }; try { const initiateUpload = await axios.request(config); logger.log(`successfully initiated ${initiateUpload}`); makeUploadRequest(initiateUpload, asset.sourceUrl, asset.fileName, logger) } catch (err) { logger.error(`error in uploading assets ${JSON.stringify(err)}`); } }; export const uploadAsset = (assets) => { const logger = Core.Logger("main"); assets.forEach((asset) => { initiateUpload(asset, logger); }); };