I try to make upload to google cloud storage use nodejs , and I get some error
This is the code
const express = require("express");
const app = express();
app.use(express.json());
// Imports the Google Cloud client library
const { Storage } = require("#google-cloud/storage");
const storage = new Storage({
keyFilename: "jerk-70c86hks6f0c.json",
projectId: "jerk",
});
const bucketName = "mystorage";
module.exports = {
upload: (myfile, videoid) => {
return (await storage.bucket(bucketName).upload(myfile.path, {
gzip: true,
destination: "kids/video/"+{videoid}+".mp4",
metadata: {
cacheControl: "public, max-age=31536000",
},
}));
},
};
This is the result
return (await storage.bucket(bucketName).upload(myfile.path, {
^^^^^^^
SyntaxError: Unexpected identifier
Can you guys explain to me why error ? , thank you :D
The error that you are getting is because it didn't expect storage to be there. The error is due to await. You only use await in an async function.
Either make your function async or remove that await.
Here is an example:
async function myAsyncFunction() {
let result = await lengthyFunction();
console.log(result);
}
myAsyncFunction();
Also here you can see an example in the documentation where the upload is not being called in an async way since it is not inside of an async function
Related
I have checked other similar post but its still not working: Its giving me undefined when console.log. I also defined the multer middleware according to other posts so I don't know what happened. But when I upload an image through postman it works with returning an 201as expected. Any help is appreciated!
ReactJS function:
const UploadImageToBackend = async () => {
console.log(UploadedImage) //UploadedImage is something like /Users/.../.jpg
let formData = new FormData()
formData.append('profile',
{name : new Date() + "_profile", uri: UploadedImage, type:'image/jpg'})
try{
const res = await client.post('/upload-avatar',formData, {
headers:{
Accept : 'application/json',
authorization: 'JWT some JWT'
},
})
console.log(res.data)
}catch(error){
console.log(error.response.data) //gives "Error while uploading Image, try after some time" error
}
}
Backend Routes:
const fileFilter = (req,file,callback) => {
if (file.mimetype.startsWith('image')){
callback(null,true)
}else{
callback('invalid image file', false)
}
}
const storage = multer.diskStorage({})
const uploads = multer({storage, fileFilter})
router.post('/upload-avatar',isAuth, uploads.single('profile'),uploadProfile)
backend upload function (to Cloudinary)
exports.uploadProfile = async (req,res)=>{
const user = req.user
if (!user){
return res.status(401).json({success:false,message:"unauthorized access!"})
}else{
console.log(req.file.path) //undefined
try{
const upload_result = await cloudinary.uploader.upload(req.file.path, {
public_id: `${user._id}_profile`,
width:500,
height:500,
crop: 'fill'
})
await User.findByIdAndUpdate(user._id, {avatar: upload_result.url})
res.status(201).json({success:true,message: "Profile picture successfully uploaded"})
}catch (error){
res.status(500).json({success:false,message:
"Error while uploading Image, try after some time"})
}
}
}
create this function (to upload into Cloudinary), e.g. "lib/cloudinary.js" and add this code:
import cloudinary from "cloudinary";
cloudinary.config({
cloud_name: "YOUR_CLOUD_NAME",
api_key: "YOUR_API_KEY",
api_secret: "YOUR_API_SECRET",
});
const upload = {};
upload.subir = async (file) => {
try {
const res = await cloudinary.uploader.upload(file);
// return the secure url
return res.secure_url;
} catch (error) {
return error;
}
}
export default upload;
Now in your controller, e.g. add this code, do not forget to install express-fileupload:
import cloudinary from "../lib/cloudinary.js";
const upload = {};
upload.uploadProfile = async (req, res) => {
const a_file = await cloudinary.subir(req.files.a_file.tempFilePath);
// show the secure url, e.g.:
// https://res.cloudinary.com/xx/image/upload/yy/winter.jpg
console.log(a_file);
// ... more code
}
export default upload;
Now in your main application e.g., "app.js" add this code to use the express middleware for uploading files:
import express from 'express';
import fileUpload from 'express-fileupload';
const app = express();
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.use(fileUpload({useTempFiles: true}));
// ... more code
Test the function using postman and the file has been uploaded
NOTE: Do not forget and
remember that this only is an alternative, exist anothers many ways i hope you understand and i hope it works for you
I'm trying to write a header of an MD5 hash token using crypto then return it back as a response. For some reason, it isn't actually running synchronously. I know JS is an asynchronous language, and that's really the only part I'm struggling with right now. Any help would be appreciated.
This is what I have so far:
const crypto = require('crypto');
const bodyParser = require('body-parser');
const formidable = require('formidable');
const async = require('async')
app.post('/pushurl/auth', (req, res) =>
var data = req.body.form1data1 + '§' + req.body.form1data2
async.waterfall([
function(callback) {
var token = crypto.createHash('md5').update(data).digest("hex");
callback(null, token);
},
function(token, callback) {
res.writeHead(301,
{Location: '/dashboard?token=' + token}
);
callback(null)
},
function(callback) {
res.end();
callback(null)
}
]);
}
});
Output:
Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
<node_internals>/internal/errors.js:256
No debugger available, can not send 'variables'
Process exited with code 1
JavaScript is an asynchronous language, yes, but it can also do synchronous tasks very well. In your case, you don't need to do any async expect if you're dealing with promises.
If you write your code like in the example below it will just execute from top to bottom.
But the error (probably) occurred because you forgot to add an opening curly brace to your app.post callback, which results in the data var being immediately returned because of an implied return statement () => (implied), () => {} (explicit).
const crypto = require('crypto');
const bodyParser = require('body-parser');
const formidable = require('formidable');
app.post('/pushurl/auth', (req, res) => {
const data = req.body.form1data1 + '§' + req.body.form1data2;
const token = crypto.createHash('md5').update(data).digest("hex");
res.writeHead(301, {
Location: '/dashboard?token=' + token
});
res.end();
});
I'm kinda new to module creation and was wondering about module.exports and waiting for async functions (like a mongo connect function for example) to complete and exporting the result. The variables get properly defined using async/await in the module, but when trying to log them by requiring the module, they show up as undefined. If someone could point me in the right direction, that'd be great. Here's the code I've got so far:
// module.js
const MongoClient = require('mongodb').MongoClient
const mongo_host = '127.0.0.1'
const mongo_db = 'test'
const mongo_port = '27017';
(async module => {
var client, db
var url = `mongodb://${mongo_host}:${mongo_port}/${mongo_db}`
try {
// Use connect method to connect to the Server
client = await MongoClient.connect(url, {
useNewUrlParser: true
})
db = client.db(mongo_db)
} catch (err) {
console.error(err)
} finally {
// Exporting mongo just to test things
console.log(client) // Just to test things I tried logging the client here and it works. It doesn't show 'undefined' like test.js does when trying to console.log it from there
module.exports = {
client,
db
}
}
})(module)
And here's the js that requires the module
// test.js
const {client} = require('./module')
console.log(client) // Logs 'undefined'
I'm fairly familiar with js and am still actively learning and looking into things like async/await and like features, but yeah... I can't really figure that one out
You have to export synchronously, so its impossible to export client and db directly. However you could export a Promise that resolves to client and db:
module.exports = (async function() {
const client = await MongoClient.connect(url, {
useNewUrlParser: true
});
const db = client.db(mongo_db);
return { client, db };
})();
So then you can import it as:
const {client, db} = await require("yourmodule");
(that has to be in an async function itself)
PS: console.error(err) is not a proper error handler, if you cant handle the error just crash
the solution provided above by #Jonas Wilms is working but requires to call requires in an async function each time we want to reuse the connection. an alternative way is to use a callback function to return the mongoDB client object.
mongo.js:
const MongoClient = require('mongodb').MongoClient;
const uri = "mongodb+srv://<user>:<pwd>#<host and port>?retryWrites=true";
const mongoClient = async function(cb) {
const client = await MongoClient.connect(uri, {
useNewUrlParser: true
});
cb(client);
};
module.exports = {mongoClient}
then we can use mongoClient method in a diffrent file(express route or any other js file).
app.js:
var client;
const mongo = require('path to mongo.js');
mongo.mongoClient((connection) => {
client = connection;
});
//declare express app and listen....
//simple post reuest to store a student..
app.post('/', async (req, res, next) => {
const newStudent = {
name: req.body.name,
description: req.body.description,
studentId: req.body.studetId,
image: req.body.image
};
try
{
await client.db('university').collection('students').insertOne({newStudent});
}
catch(err)
{
console.log(err);
return res.status(500).json({ error: err});
}
return res.status(201).json({ message: 'Student added'});
};
I'm attempting to handle file uploads using a Google Cloud Function. This function uses Busboy to parse the multipart form data and then upload to Google Cloud Storage.
I keep receiving the same error: ERROR: { Error: ENOENT: no such file or directory, open '/tmp/xxx.png' error when triggering the function.
The error seems to occur within the finish callback function when storage.bucket.upload(file) attempts to open the file path /tmp/xxx.png.
Note that I can't generate a signed upload URL as suggested in this question since the application invoking this is an external, non-user application. I also can't upload directly to GCS since I'll be needing to make custom filenames based on some request metadata. Should I just be using Google App Engine instead?
Function code:
const path = require('path');
const os = require('os');
const fs = require('fs');
const Busboy = require('busboy');
const Storage = require('#google-cloud/storage');
const _ = require('lodash');
const projectId = 'xxx';
const bucketName = 'xxx';
const storage = new Storage({
projectId: projectId,
});
exports.uploadFile = (req, res) => {
if (req.method === 'POST') {
const busboy = new Busboy({ headers: req.headers });
const uploads = []
const tmpdir = os.tmpdir();
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
const filepath = path.join(tmpdir, filename)
var obj = {
path: filepath,
name: filename
}
uploads.push(obj);
var writeStream = fs.createWriteStream(obj.path);
file.pipe(writeStream);
});
busboy.on('finish', () => {
_.forEach(uploads, function(file) {
storage
.bucket(bucketName)
.upload(file.path, {name: file.name})
.then(() => {
console.log(`${file.name} uploaded to ${bucketName}.`);
})
.catch(err => {
console.error('ERROR:', err);
});
fs.unlinkSync(file.path);
})
res.end()
});
busboy.end(req.rawBody);
} else {
res.status(405).end();
}
}
I eventually gave up on using Busboy. The latest versions of Google Cloud Functions support both Python and Node 8. In node 8, I just put everything into async/await functions and it works fine.
i store my image on firebase storage now i wanted to display it on my page
const firebase = require('./../config/firebase');
const gcloud = require('google-cloud');
const fs = require('fs');
var storage = gcloud.storage({
projectId: 'test-a1e76',
keyFilename: 'test-a1e76-firebase-adminsdk-7111d-124guy123eac.json',
});
var bucket = storage.bucket('test-a1e76.appspot.com');
this is how my set up looks like.
and this is my get method.
router.get('/image', function (req,res) {
var remoteReadStream = bucket.file('download.png').createReadStream();
var localWriteStream = fs.createWriteStream('/images/watchers/2jIompF9FUZ6A4LnpBcbpHWw8dx2/download.png');
var ss = remoteReadStream.pipe(localWriteStream);
res.send(ss);
})
i only tried this since it was written on the npm docs.of google-cloud works.
i tried putting it inside get method to see how it works.
and after that i got this error..
Error: ENOENT: no such file or directory, open 'C:\images\test\2jIoasd24zd13ase121s2Ww8dx2\download.png'
this is my ajax get method
$.ajax({
url:'/user/image',
type:'GET',
success:function(data){
console.log(data.path);
}
});
can anyone here guide my on how can i retrieve the images from firebase storage and display it on my webpage?. using this google-cloud npm? cause i read some thread that node js doesn't support firebase-storage so they use google-cloud instead.
I got it working this way.
var admin = require("firebase-admin");
...
app.get('/picture', async (req, res) => {
const fileRef = admin.storage().bucket().file('03aead66e97f0d50ce549b6fffc1b6d7.svg');
const hash = await fileRef.download()
res.contentType(fileRef.metadata.contentType);
res.end(hash[0], 'binary');
});
You need only show the image, right? There`s a dirty way to do.
1- Upload one image on your bucket e click on it (in Firebase console).
2- In the right side of screen shows info about your file.
3- Look for "Download Url" (or something like that) and click on it.
4- This is a url example:
https://firebasestorage.googleapis.com/v0/b/coffee-a7e8c.appspot.com/o/coffeeTrue.png?alt=media&token=7f44e575-414d-4d18-8f39-c94a23f6e014
As you can see there is a pattern:
https://firebasestorage.googleapis.com/v0/b/NAME_FILE?alt=media&token=YOUR_TOKEN
Get your token and now you can show all images on your bucket only pass de name of file and your token (like this example).
This works because Firebase provides a Rest API for your services.
Remember: Do auth before or set-up open rules.
Example: Everyone can read. Only auth user can write.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if request.auth == null;
allow write: if request.auth != null;
}
}
}
In the firebase function with node I use below code which is working perfectly
How do I upload a base64 encoded image (string) directly to a Google Cloud Storage bucket using Node.js?
const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
const os = require('os')
const path = require('path')
const cors = require('cors')({ origin: true })
const Busboy = require('busboy')
const fs = require('fs')
var admin = require("firebase-admin");
var serviceAccount = {
"type": "service_account",
"project_id": "xxxxxx",
"private_key_id": "xxxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
"client_email": "xxxx#xxxx.iam.gserviceaccount.com",
"client_id": "xxxxxxxx",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
}
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "xxxxx-xxxx" // use your storage bucket name
});
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
response.set('Access-Control-Allow-Origin', '*');
const busboy = new Busboy({ headers: req.headers })
let uploadData = null
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
const filepath = path.join(os.tmpdir(), filename)
uploadData = { file: filepath, type: mimetype }
console.log("-------------->>",filepath)
file.pipe(fs.createWriteStream(filepath))
})
busboy.on('finish', () => {
const bucket = admin.storage().bucket();
bucket.upload(uploadData.file, {
uploadType: 'media',
metadata: {
metadata: { firebaseStorageDownloadTokens: uuid,
contentType: uploadData.type,
},
},
})
.catch(err => {
res.status(500).json({
error: err,
})
})
})
busboy.end(req.rawBody)
});
exports.widgets = functions.https.onRequest(app);