Missing required parameter - file Cloudinary \Error - javascript

first time trying to upload images to Cloudinary and I have come across an issue Missing required parameter- file
In this way I'm Configuring my cloudinary
//Configuring Cloudinary
cloudinary.config({
cloud_name: process.env.ClOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY ,
api_secret: process.env.CLOUDINARY_API_SECRET,
})
Im using this to add user avatar on cloudinary like this:
//Register user
exports.registerUser = catchAsyncError(async (req, res, next) => {
//avatar img upload
const myCloud = await cloudinary.v2.uploader.upload(req.body.avatar, {
folder: "avatars",
width: 150,
crop: "scale",
});
const { name, email, password } = req.body;
const user = await User.create({
name,
email,
password,
avatar: {
public_id: myCloud.public_id,
url: myCloud.secure_url,
},
});
This is how i am setting the FormData
const registerSubmit = (e) => {
e.preventDefault();
const myForm = new FormData();
myForm.set("name", name);
myForm.set("email", email);
myForm.set("password", password);
myForm.set("avatar", avatar);
dispatch(register(myForm));
};
//For Register
export const register = ({userData}) => async (dispatch) =>{
try{
dispatch({type: REGISTER_USER_REQUEST});
const config = { headers : {"Content-Type": "multipart/form-data"} };
const {data} = await axios.post(
`api/v1/register`,
{userData},
{config}
);
dispatch({type:REGISTER_USER_SUCCESS, payload: data.user});
}
catch(error){
dispatch({type:REGISTER_USER_FAIL, payload:error.response.data.message});
}
but after all this I'm still getting the same error, Please help me

Related

PDF along with text not getting uploaded to Express from React

I want to send book details along with the pdf of the book to the database.
This is a portion of my react code.
const {user}=useSelector((state)=>state.auth)
const [file, setFile] = useState(null);
const dispatch = useDispatch()
const { values, errors, touched, handleBlur, handleChange, handleSubmit, setFieldValue } = useFormik({
initialValues: initialValues,
validationSchema: addBookSchema,
onSubmit: async(values, { resetForm }) => {
// i have used FormData only to send pdf
const formData = new FormData()
formData.append('title', values.title)
formData.append('author', values.author)
formData.append('rating', values.rating)
formData.append('numOfRatings', values.numOfRatings)
formData.append('total', values.total)
formData.append('genre', values.genre)
formData.append('file', file)
const response = await axios.post('http://localhost:5000/api/admin', formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${user.token}`,
},
});
console.log(response.data);
resetForm()
}
})
return (
// some code
<Box>
<TextField
id="pdf-input"
// label="Upload PDF"
type="file"
accept=".pdf"
// className={classes.textField}
onChange={handleFileChange}
margin="normal"
/>
</Box>
// some code
Below is my express controller which handles this input from react
// this is to start connection
const url = process.env.MONGO_URI;
const connect = mongoose.createConnection(url, { useNewUrlParser: true, useUnifiedTopology: true });
let gfs;
connect.once('open', () => {
// initialize stream
gfs = new mongoose.mongo.GridFSBucket(connect.db, {
bucketName: "uploads"
});
});
// this is the controller
const addBook = asyncHandler(upload.single('file'),async (req, res) => {
console.log(req.file.file);
console.log(req.body);
// nothing gets logged in console
res.status(200).json(req.body)
});
below is my upload middleware used in my controller
const path = require("path");
const multer = require("multer");
const { GridFsStorage } = require("multer-gridfs-storage");
const crypto = require("crypto");
const storage = new GridFsStorage({
url: process.env.MONGO_URI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "uploads",
};
resolve(fileInfo);
});
});
},
});
const upload = multer({ storage });
module.exports = upload;
i get the following errors
//1. if i do formData.append('file', file) then i get "Warning: An unhandled error was caught from submitForm()"
//2. if i do formData.append('ebook', file) then i get "message: 'Unexpected field', stack: 'MulterError: Unexpected field\n"
//3. Nothing gets logged in my console when i console.log(req.body) in my controller.
Note: I am able to successfully send data to my database if i do not use FormData and do not take file input.
I tried various methods but i could not identify the problem. Any helps is very much appreciated. Thanks in advance.

How do I upload images from external URLs onto Firebase? (using next.js)

Basically I'm using next.js and I'm making a program that generates images using Openai's Dalle2 API (artificial intelligence), and then uploads it onto my firebase storage. How do I download these images when they are generated and upload them to the firebase storage? Everytime i try, I just end up getting a 'application/octet-stream' file type uploaded and it doesn't work.
This is my code:
const [selectedFile, setSelectedFile] = useState(null);
const generateImage = async () => {
console.log('openai image start')
const prompt = captionRef.current.value
try {
const response = await openai.createImage({
prompt: prompt,
n: 1,
size: "256x256",
})
const imageUrl = response.data.data[0].url
console.log('openai image generated')
setSelectedFile(imageUrl)
console.log(selectedFile)
} catch (error) {
if (error.response) {
console.log(error.response.status);
console.log(error.response.data);
} else {
console.log(error.message);
}
}
}
const uploadPost = async () => {
if (loading) return;
setLoading(true);
//create post and add to firestore posts collection
//get post id for new post
//upload image to firebase storage with post id
//get a download url from firebase storage and update original post with image
const docRef = await addDoc(collection(db, 'posts'), {
username: session.user.username,
caption: captionRef.current.value,
profileImg: session.user.image,
timestamp: serverTimestamp()
})
console.log("New doc added with ID", docRef.id);
console.log(selectedFile)
//**PROBLEM**
const imageRef = ref(storage, `posts/${docRef.id}/image`)
await uploadBytes(imageRef, selectedFile).then(async snapshot => {
const downloadURL = await getDownloadURL(imageRef)
await updateDoc(doc(db, 'posts', docRef.id), {
image: downloadURL
})
})
setLoading(false)
setSelectedFile(null)
}

Cannot send cloudinary public_id and url to backend - Next JS

I am making an expense tracker and accounting app for my client. I have added a file input and upload those file to cloudinary and store public_id and secure_url in backend and database. I am using Next JS for frontend and backend. I am getting following errors.
I have added unsigned upload_preset here is the image of my cloudinary settings page.
One more thing this code works some time and don't show this error instead it mood change and shows error that I have not provided public_id or secure_url in backend database.
here is the code:
Frontend:
const handleSubmit = async (e) => {
e.preventDefault();
const form = e.currentTarget;
const miningInput = Array.from(form.elements).find(
({ name }) => name === "miningPapers"
);
const miningFormData = new FormData();
for (const file of miningInput.files) {
miningFormData.append("file", file);
}
miningFormData.append("upload_preset", "mining-papers");
const miningRes = await axios.post(
"https://api.cloudinary.com/v1_1/cloudName/image/upload",
miningFormData
);
const insuranceInput = Array.from(form.elements).find(
({ name }) => name === "insurancePapers"
);
const insuranceFormData = new FormData();
for (const file of insuranceInput.files) {
insuranceFormData.append("file", file);
}
insuranceFormData.append("upload_preset", "insurance-papers");
const insuranceRes = await axios.post(
"https://api.cloudinary.com/v1_1/cloudName/image/upload",
insuranceFormData
);
const insurancePubId = insuranceRes.data.public_id;
const insuranceUrl = insuranceRes.data.secure_url;
const miningPapersPubId = miningRes.data.public_id;
const miningUrl = miningRes.data.secure_url;
dispatch(
create(
//Other Data
//ERROR here \/
{
insurancePapers: {
public_id: insuranceRes.data.public_id,
url: insuranceRes.data.secure_url,
},
},
//ERROR here \/
{
miningPapers: {
public_id: miningRes.data.public_id,
url: miningRes.data.secure_url,
},
},
)
)
}
Dispatch function:
export const create = (insurancePapers, miningPapers)=> async(dispatch)=>{
dispatch({ type: ADD_DISPATCH_REQUEST });
const { data } = await axiosInstance.post(`/api/dispatch/create`,{
insurancePapers
miningPapers
})
dispatch({
type: ADD_DISPATCH_SUCCESS,
payload: data,
});
}
Backend:
const handler = async (req, res) => {
if (req.method === "POST") {
let reciept = await DispatchReceipt.findOne({
ICDN_No: req.body.ICDN_No,
});
if (reciept) {
return res
.status(409)
.json("Dispatch Receipt With this ICDN Number already exists");
}
if (req.body.differenceInQty) {
req.body.differenceInQty =
req.body.loadedMaterialQty - req.body.unloadedMaterialQty;
} else {
req.body.differenceInQty = 0;
}
//Creating Dispatch Receipt
reciept = await DispatchReceipt.create(req.body);
//Adding receipt ID to customer
const customer = await Customer.findOne({ name: req.body.party });
if (!customer) {
res.status(404).json("Customer Not Found");
}
if (customer) {
customer.dispatchReceipts.push(reciept._id);
customer.save();
}
//response
res.status(200).json(reciept);
} else {
return res.status(500).send("INVALID REQUEST");
}
};
Backend MongoDB Models :
const DispatchReceiptSchema = new mongoose.Schema({
//Other data
//ERROR here \/
insurancePapers: {
public_id: { type: String, required:[true, "Please add public ID"] },
url: { type: String , required:[true, "Please add url"]},
},
//ERROR here \/
miningPapers: {
public_id: {
type: String,
required: [true, "Please Upload Mining Papers"],
},
url: { type: String, required: [true, "Please Upload Mining Papers"] },
},
});
mongoose.models = {};
const DispatchReceipt = mongoose.model(
"DispatchReceipt",
DispatchReceiptSchema
);
export default DispatchReceipt;

How to update files using Axios and React

I've built an api with posts/articles, and now I'm working on the front end. I'm having an issue with uploading a new photo for an already existing post. I've attempted the two most common methods for the photo, formData and JSON Base64. I'm receiving the same error response for both methods, Please upload a file, code: 400. I'm not certain where I've gone wrong, so I'll provide every relevant file.
articles.js(server)
exports.articlePhotoUpload = asyncHandler(async (req, res, next) => {
const article = await Article.findById(req.params.id);
if (!article) {
return next(
new ErrorResponse(`Article not found with id of ${ req.params.id }`, 404)
);
}
//Make sure user is article owner || make sure user is admin
if (article.user.toString() !== req.user.id || req.user.role !== 'admin') {
return next(
new ErrorResponse(
`User ${ req.user.id } is not authorized to update this article`,
)
)
}
if (!req.files) {
return next(new ErrorResponse(`Please upload a file`, 400))
}
const file = req.files.file;
// Confirm the image is a photo
if (!file.mimetype.startsWith('image')) {
return next(new ErrorResponse(`Please upload an image file`, 400))
}
// Check File Size
if (file.size > process.env.MAX_FILE_UPLOAD) {
return next(
new ErrorResponse(`Please upload an image less than ${ MAX_FILE_UPLOAD }`, 400)
)
}
// Create custom filename
file.name = `photo_${ article._id }${ path.parse(file.name).ext }`;
file.mv(`${ process.env.FILE_UPLOAD_PATH }/${ file.name }`, async err => {
if (err) {
console.log(err);
new ErrorResponse(`Problem with file upload`, 500);
}
await Article.findByIdAndUpdate(req.params.id, { photo: file.name });
res.status(200).json({
success: true,
data: file.name
});
});
});
^the above function is where the error message is triggered server-side.
axios.js(client-side)
...
axios.defaults.baseURL = 'http://<<ip address>>/api/v1';
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('auth');
axios.defaults.headers.post['Content-Type'] = 'application/json';
export const uploadPhoto = (id, data) => {
return axios.put(`/articles/${ id }/photo`, {
data
})
}
...
^I have a feeling I could format this exported function better. I might be missing something here.
UploadPhoto.jsx(JSON Attempt)
const UploadPhoto = (props) => {
const { register, handleSubmit } = useForm();
const { state } = useStateMachine(updateAction);
const [file, setFile] = useState(null);
const [filename, setFilename] = useState(null);
const onSubmit = async () => {
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
console.log(reader.result)
});
const data = {
title: filename,
file: await toBase64(file),
}
uploadPhoto(`5ea5e73044718d0b2c2ae5df`, data)
.then(res => console.log(res))
.catch(err => console.log(err.response.data.error))
}
const handleChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h2>Cover Image</h2>
<label>
Select A File:
</label>
<img id="image" src="" alt="" />
<input
type="file"
name="photo"
ref={register}
defaultValue={state.data.photo}
onChange={handleChange}
/>
<label htmlFor="">
Filename
</label>
<input type="submit" />
</form>
)
}
export default withRouter(UploadPhoto);
UploadPhoto.jsx(formData attempt)
const onSubmit = () => {
const formData = new FormData();
formData.append("file", file);
console.log(file)
uploadPhoto(`5ea5e73044718d0b2c2ae5df`, formData)
.then(res => console.log(res))
.catch(err => console.log(err.response.data.error))
}
This is my first time building my own api, which is why I put the server code in here. However, I'm 90% sure I'm making a mistake client-side, most likely in the axios.js file.
Let's try this example:
const fileUpload = require('express-fileupload');
const app = express();
// enable files upload -- this should also make 'req.files' accessible
app.use(fileUpload({
createParentPath: true
}));
Add this in the beginning of your server initialization. After that your normal code should try accessing req.files as it should be filled on file upload requests now.
You will need to install module express-fileupload before using it in code -> npm i express-fileupload
(Source: https://attacomsian.com/blog/uploading-files-nodejs-express)

Upload Image from form-data to S3 using a Lambda

So I am writing a Lambda that will take in some form data via a straight POST through API Gateway (testing using Postman for now) and then send that image to S3 for storage. Every time I run it, the image uploaded to S3 is corrupted and won't open properly. I have seen people having to decode/encode the incoming data but I feel like I have tried everything using Buffer.from. I am only looking to store either .png or .jpg. The below code does not reflect my attempts using Base64 encoding/decoding seeing they all failed. Here is what I have so far -
Sample Request in postman
{
image: (uploaded .jpg/.png),
metadata: {tag: 'iPhone'}
}
Lambda
const AWS = require('aws-sdk')
const multipart = require('aws-lambda-multipart-parser')
const s3 = new AWS.S3();
exports.handler = async (event) => {
const form = multipart.parse(event, false)
const s3_response = await upload_s3(form)
return {
statusCode: '200',
body: JSON.stringify({ data: data })
}
};
const upload_s3 = async (form) => {
const uniqueId = Math.random().toString(36).substr(2, 9);
const key = `${uniqueId}_${form.image.filename}`
const request = {
Bucket: 'bucket-name',
Key: key,
Body: form.image.content,
ContentType: form.image.contentType,
}
try {
const data = await s3.putObject(request).promise()
return data
} catch (e) {
console.log('Error uploading to S3: ', e)
return e
}
}
EDIT:
I am now atempting to save the image into the /tmp directory then use a read stream to upload to s3. Here is some code for that
s3 upload function
const AWS = require('aws-sdk')
const fs = require('fs')
const s3 = new AWS.S3()
module.exports = {
upload: (file) => {
return new Promise((resolve, reject) => {
const key = `${Date.now()}.${file.extension}`
const bodyStream = fs.createReadStream(file.path)
const params = {
Bucket: process.env.S3_BucketName,
Key: key,
Body: bodyStream,
ContentType: file.type
}
s3.upload(params, (err, data) => {
if (err) {
return reject(err)
}
return resolve(data)
}
)
})
}
}
form parser function
const busboy = require('busboy')
module.exports = {
parse: (req, temp) => {
const ctype = req.headers['Content-Type'] || req.headers['content-type']
let parsed_file = {}
return new Promise((resolve) => {
try {
const bb = new busboy({
headers: { 'content-type': ctype },
limits: {
fileSize: 31457280,
files: 1,
}
})
bb.on('file', function (fieldname, file, filename, encoding, mimetype) {
const stream = temp.createWriteStream()
const ext = filename.split('.')[1]
console.log('parser -- ext ', ext)
parsed_file = { name: filename, path: stream.path, f: file, type: mimetype, extension: ext }
file.pipe(stream)
}).on('finish', () => {
resolve(parsed_file)
}).on('error', err => {
console.err(err)
resolve({ err: 'Form data is invalid: parsing error' })
})
if (req.end) {
req.pipe(bb)
} else {
bb.write(req.body, req.isBase64Encoded ? 'base64' : 'binary')
}
return bb.end()
} catch (e) {
console.error(e)
return resolve({ err: 'Form data is invalid: parsing error' })
}
})
}
}
handler
const form_parser = require('./form-parser').parse
const s3_upload = require('./s3-upload').upload
const temp = require('temp')
exports.handler = async (event, context) => {
temp.track()
const parsed_file = await form_parser(event, temp)
console.log('index -- parsed form', parsed_file)
const result = await s3_upload(parsed_file)
console.log('index -- s3 result', result)
temp.cleanup()
return {
statusCode: '200',
body: JSON.stringify(result)
}
}
The above edited code is a combination of other code and a github repo I found that is trying to achieve the same results. Even with this solution the file is still corrupted
Figured out this issue. Code works perfectly fine - it was an issue with API Gateway. Need to go into the API Gateway settings and set thee Binary Media Type to multipart/form-data then re-deploy the API. Hope this helps someone else who is banging their head against the wall on figuring out sending images via form data to a lambda.

Categories