How to send in Angular http post request with data + image? - node.js

In a post request (in Angular), I usually send data (for example like 'product' data) using an 'object':
product: any = {}; // filled of proprieties (code, barcode, name, description...)
and then pass this in the request:
return this.http
.post<any>( Url , product)
.pipe(catchError(this.errorHandler));
using ExpressJS I can easly retrieve the proprieties 'req.body.<< propriety >>' :
router.post("/newProduct", function (req, res, next) {
const code = req.body.code;
const barcode = req.body.barcode;
const nameProduct = req.body.name;
const description = req.body.description;
//.. here other code - mySql to insert data in the DB ..
});
THE PROBLEM
Now I would like to send the same data (like in the example) and also an image to save on the server.
PS
I tried to use FormData:
var formData = new FormData();
formData.append('image', imageFile);
formData.append('product', product);
return this.http
.post<any>(this.newProductUrl, formData )
.pipe(catchError(this.errorHandler));
So in the backend, I can retrieve and save the image using the npm package 'multer' but then I don't know how to get the 'product' data.

You can access your image data added in formData with 'request.file' and your others data will be available on 'request.body'
To Upload the image in backend multer.upload('image') will be used. Here image is the key that you have in your formdata.
// frontend
var formData = new FormData();
formData.append('image', imageFile);
formData.append('product', product);
// backend
var upload = multer({ dest: 'uploads/' }) // uploads your destination folder
app.post('/profile', upload.single('image'), function (req, res, next) {
// req.file is the `image` file
// req.body will hold the text fields, if there were any
});

Related

How to get uploaded image in react by url?

I want to realize uploading files for my users. I use CKEDITOR 5 in my react project. Back-end on nodeJS.
So, i can upload file, can get its Url, but, can't display one in VIEW page.
//my server code
const express = require('express');
//for uploading i use this module
const multiparty = require('connect-multiparty');
const multipartyMiddleware = multiparty({uploadDir: '/var/www/group0384.ru/public_html/server/uploads'}) //here is whole path to my upload folder on server
const app = express();
const port = 3555;
const path = require('path');
const moment = require('moment');
const fs = require('fs');
//so, here i have route /upload, which is indicated in configuration of ckeditor as route to send pictures
app.use(express.static("uploaded"));
app.post('/upload', multipartyMiddleware, (req, res) => {
var TempFile = req.files.upload;
var TempPathfile = TempFile.path;
const targetPathUrl = path.join(__dirname,"./uploaded/"+TempFile.name);
if(path.extname(TempFile.originalFilename).toLowerCase() === ".png" || ".jpg"){
fs.rename(TempPathfile, targetPathUrl, err =>{
res.status(200).json({
uploaded: true,
url: `${__dirname}/uploaded/${TempFile.originalFilename}`
}); // this path is the same as in 5th row (except folder, here it change, but it's no matter)
if(err) return console.log(err);
})
}
})
//------------CKEDITOR CODE---//
<CKEditor
editor={ClassicEditor}
data={this.state.data}
onChange={(event, editor) => {
this.setState({
data: editor.getData(),
});
}}
config={
{
ckfinder: {
uploadUrl: '/upload'
} // here, /upload - the route to send pictures
}
}
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
On my VIEW page, i getting this
screenshot
So, i've tried to change paths, but still couldn't get the picture.
please explain why I can't just get and output a file that is already uploaded on my own server
P.S. Sorry for my english
It seems from the screenshot that you are getting the absolute path to the image, if you want to show the image on the client-side and you are sure the image is saved on your server, you have to send it back as a public URL address of your image!
example: "http://example.com/images/image1.png"
Thank you all for answers, i resolved the problem.
In this part i change url for uploaded images
res.status(200).json({
uploaded: true,
url: `/files/${TempFile.originalFilename}`
});
Then, i created route with this url
app.get('/files/:url(*)', (req, res) => {
console.log(req.params.url)
res.sendFile(path.resolve(__dirname + '/uploaded/' + req.params.url))
})
And it works!

Is there any way to accept binary data type like pdf in serverless?

I am facing the issue like the following:
When uploading a pdf file in vue.js to serverless node.js application, file content is broken.
Because the serverless parses binary data type incorrectly, it happens the issue.
How can I accept binary data type like pdf correctly or other method to solve the issue?
// Vue.js
let formData = new FormData();
formData.append('file', fileObj);
axios.post(API_ENDPOINT + '/upload', formData).then(resp => {
console.log(resp);
})
// Serverless Express
const express = require('express');
const app = express();
const fileUpload = require('express-fileupload');
app.use(fileUpload());
app.post('/upload', (req, res) => {
console.log(req.files.file) // Uploaded tmp file - It has broken content
});
Currently I am using multiparty. I will provide the middleware in the following snippet of code
const { Form } = require('multiparty')
function formDataParser(req, res, next) {
if (!req.is('multipart/form-data')) {
next();
return;
}
const form = new Form();
form.parse(req, (err, fields, files) => {
if (err) {
res.status(400).json({
message: 'Could not parse multipart form.'
});
return;
}
const fieldsKeys = Object.keys(fields);
for (const fieldKey of fieldsKeys) {
fields[fieldKey] = fields[fieldKey][0];
}
req.form = {
fields,
files
}
next();
});
}
module.exports = formDataParser;
I suggest not to attach this middleware as a global one but instead use it only on specific routes that need it. With the provided solution you can access form fields in the following way:
req.form.fields.somefield

Express, Multer, and Cloudinary not returning full cloudinary response

I'm using Multer/multer-storage-cloudinary to upload images directly to Cloudinary rather first uploading it to a local temp directory, then sending it to Cloudinary:
const express = require('express');
const router = express.Router({mergeParams:true});
if (app.get('env') == 'development'){ require('dotenv').config(); }
const crypto = require('crypto');
const cloudinary = require('cloudinary').v2;
const { CloudinaryStorage } = require('multer-storage-cloudinary');
const multer = require('multer');
const { storage } = require('../cloudinary');
const upload = multer({storage});
//configure cloudinary upload settings
cloudinary.config({
cloud_name:process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET
});
const storage = new CloudinaryStorage({
cloudinary: cloudinary,
folder: ('book_tracker/'+process.env.CLOUDINARY_FOLDER+'posts'),
allowedFormats: ['jpeg', 'jpg', 'png'],
filename: function (req, file, cb) {
let buf = crypto.randomBytes(16);
buf = buf.toString('hex');
let uniqFileName = file.originalname.replace(/\.jpeg|\.jpg|\.png/ig, '');
uniqFileName += buf;
console.log(req.body);
cb(undefined, uniqFileName );
}
});
const middleware = {
function asyncErrorHandler: (fn) =>
(req, res, next) => {
Promise.resolve(fn(req, res, next))
.catch(next);
}
}
/* POST create user page */
router.post('/register', upload.single('image'), asyncErrorHandler(postRegister));
What I'm running into is that the response I'm getting in req.file is not the full Cloudinary response which includes public_id, etc. Instead it's like this:
{
fieldname: 'image',
originalname: 'My Headshot.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
path: 'https://res.cloudinary.com/<cloudinary_name>/image/upload/v1611267647/<public_id>.jpg',
size: 379632,
filename: '<public_id>'
}
It's been a while since I worked with multer-storage-cloudinary, though that storage was taken directly from an old project that would return the correct information. Is there something in multer, or multer-storage-cloudinary, that I need to set in order to put the full cloudinary response into req.file?
The multer-storage-cloudinary package is a third party package that integrates multer and Cloudinary in a streamlined way, but it doesn't expose all possible options or responses from the Cloudinary SDK or API
In your example, it's not returning the full API response from Cloudinary, but a subset of the fields, because the file object's filename, path, and size properties are taken from the Cloudinary API response (from the public_id, secure_url, and bytes properties of the API response respectively), but the other fields aren't mapped: https://github.com/affanshahid/multer-storage-cloudinary#file-properties
If you need the full set of response values (or some specific values not mapped already) you can:
Ask the package maintainer to add support for other fields
Fork the package and map additional fields yourself; the fields are mapped here though I'm not sure what else may need to be changed: https://github.com/affanshahid/multer-storage-cloudinary/blob/1eb903d44ac6dd42eb1ab655b1e108acd97ed4ca/src/index.ts#L83-L86
Switch from using that package for wrapping the Cloudinary SDK to use the Cloudinary SDK directly in your own code, so you can handle the response directly.
Leave it as it is now and make a separate call to the Cloudinary Admin API to fetch the other details of the image(s): https://cloudinary.com/documentation/admin_api#get_resources
Leave it as-is, but add a notification_url so that as well as the API call response, the details of the new upload will be sent in an HTTP POST request to a URL of your choice: https://cloudinary.com/documentation/notifications
The notification_url can be specified in the Upload API call, Upload Preset, or at the account-level in the Cloudinary account settings.

How to upload file from nodeJS to nodeJS

I have 2 nodeJS services and I would want to upload file in a dir, from one NodeJS (backend) to another NodeJS(backend). The receiver nodeJS is an express app.
Looking for some working code sample.
PS: Couldn't find any code samples in search, since everywhere it was Multer from client to server uploads that receives multipart/form-data.
Uploading file using POST request in Node.js
Receive the file first as you correctly said using Multer. Then, you may either save the file to a temporary directory before uploading it again or just send the file as-is.
You need to setup a server running with Multer on the 2nd server that wishes to receive the file.
const express = require('express');
const app = express();
const upload = multer({ dest: 'files/' });
app.post('/upload', upload.single('file'), (req, res) => {
res.sendStatus(200);
});
app.listen(3001);
Then on the server you wish to send the file from, do something like this:
const request = require('request');
const req = request.post('localhost:3001/upload', (err, res, body) => {
if (err) throw new Error(err);
if (res && res.statusCode == 200) {
console.log('Success');
} else {
console.log('Error');
};
});
const form = req.form();
form.append('file', fs.createReadStream('./location/to/file'));

Nodejs convert image to byte array

That I would like to convert into a byte array.
I get the file with <v-file-input> and this is the input of it.
I would like to convert it on the client side, then send it to the backend to be uploaded to the sql server.
I've tried to search it on google for hours.
Try to add this file object to FormData and send it to nodejs. On a server side you can use multer to decode multipart formdata to req.file for instance
on a client side:
const formData = new FormData()
formData.append('file', file)
const { data: result } = await axios.post(`/api/upload-image`, formData)
on a server side:
const multer = require('multer')
const upload = multer()
...
router.post('/upload-image', upload.single('file'), uploadImageFile)
...
uploadImageFile(req, res) {
// multer writes decoded file content to req.file
const byteContent = req.file
res.end()
}

Resources