System Information
-
Strapi Version: 4.8.2
-
Operating System: Ubuntu 18.04
-
Database: sqlite
-
Node Version: v16.16.0
-
NPM Version: 8.11.0
-
Yarn Version: 1.22.19
Using Strapi lifecycle hooks, I’m creating a .jpg file when a new post is created. I wish to upload this jpg file to the Strapi media library within the same lifecycle.
I’ve tried:
let form = new FormData();
form.append('files', fs.createReadStream("./poster.jpg"));
const response = await fetch('http://localhost:1337/api/upload', {
method: 'post',
body: form,
});
but nothing happens in the console. I tried posting the same image using Postman with only the “files” field and it works Postman:
Is poster.jpg
in the same directory as the file that contains the sample code?
Explaining what you’re trying to achieve will help curate an answer - for example, is this running in a browser and you’re using a file input field, or is this running on another Node.js server and the poster.jpg
image is on that server?
Thanks for helping me explain better, Clark. This is going in src/api/card/content-types/card/lifecycles.js, within afterUpdate lifecycle hook. I’m automating poster creation using node-canvas, which outputs a poster.jpg file in the Strapi project root folder. Now I want to upload and associate the poster.jpg with event.params.data.PosterUrl. Here’s the full code:
// lifecycles.js
const { FormData } = require("formdata-node");
const fetch = require("node-fetch");
const api_url = "http://127.0.0.1:1337";
module.exports = {
async afterUpdate(event) {
let dataSource = event.params.data;
if (
dataSource.Paragraph &&
dataSource.Paragraph?.length > 0
) {
// get the image url associated with post:
const imageResource = await strapi.entityService.findOne(
"plugin::upload.file",
`${dataSource.Image}`,
{
fields: ["url"],
}
);
// convert the relative path as an absolute path to the ImageUrl field of the card content-type:
const ImageUrl = api_url + JSON.parse(JSON.stringify(imageResource)).url;
dataSource.ImageUrl = ImageUrl;
// create a canvas
const { loadImage, createCanvas } = require("canvas");
const fs = require("fs");
// Dimensions for the image
const width = 378;
const height = 662.438;
// Instantiate the canvas object
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
// Fill the rectangle with white
ctx.fillStyle = "#a14124";
ctx.fillRect(0, 0, width, height);
ctx.fillText("hello world", width, height);
// load the background image
loadImage(dataSource.ImageUrl)
.then((image) => {
// draw the background image on the canvas
ctx.drawImage(image, 0, 0, width, height);
// add Headline to the image
ctx.fillStyle = "white";
ctx.font = "bold 48px sans-serif";
ctx.textAlign = "center";
ctx.fillText(dataSource.Headline, width / 2, height / 3);
// Add Paragraph to image
ctx.fillStyle = "white";
ctx.font = "bold 48px sans-serif";
ctx.textAlign = "center";
ctx.fillText(dataSource.Paragraph, width / 2, height / 2);
// place the canvas to a JPEG buffer
const buffer = canvas.toBuffer("image/jpeg");
// save the buffer as a file
fs.writeFileSync("./poster.jpg", buffer);
})
.catch((err) => {
console.error(err);
});
// Create a form with the newly created image
const form = new FormData();
form.append('files', fs.createReadStream("./hello_world.jpg"));
// post the image to the media library
const response = await fetch('http://localhost:1337/api/upload', {
method: 'post',
body: form,
});
}
},
};
For anyone wondering how I spent my last 10 hours, here’s a working solution:
const mime = require('mime-types'); //used to detect file's mime type
const fileName = 'poster.jpg';
const filePath = `./${fileName}`
const stats = fs.statSync(filePath)
await strapi.plugins.upload.services.upload.upload({
data:{}, //mandatory declare the data(can be empty), otherwise it will give you an undefined error.
files: {
path: './poster.jpg',
name: 'poster.jpg',
type: mime.lookup(filePath), // mime type of the file
size: stats.size,
},
});
1 Like
I haven’t got time right now to go through the code line by line but a couple of things stand out to me.
-
const fileName = 'poster.jpg';
this should be a unique filename. Consider using UUID, adding a randomly generated hash, or timestamp (+new Date()
) to create a random file name.
- If you don’t change the filename, are you worried about synchronous requests picking up on the same file by other users?
- You should probably store the files in a sub-folder, not the root folder.
- Once it’s uploaded into Strapi’s media folder, you should probably delete the image (poster.jpg).
- Your image size is relatively small, any reason why it’s not bigger (> 2,000 px)? You can create a large image now and create smaller versions using Strapi’s Media Library breakpoint settings.
a) This will help later if you need to create larger versions of the images you have already generated in the past.
I hope this helps!
1 Like
@dallasclark I apologize for the extremely late reply. But thank you for sharing your thoughts. As someone who learned coding through YouTube and boot camps, I really appreciate you helping me understand best practices. This makes me think, there should be a platform where novice coders can get feedback for their projects (that is not Stackoverflow).
1 Like
Any time, I was once a beginner 