I need to send a multipart request to server with a file (document_example.pdf) and a json file that contains the data object (data_object_example.json) in Angular 7.
data_object_example.json -> {
"attribute1": "name",
"attribute2": "second_name"
}
I know how create a multipart request, but I don't know how create json file by a object.
Thanks. ;)
Answer: Thanks to HaiTH
const docJson = {
fileDocType: file.name.split('?')[0].split('.').pop(),
fileName: file.name
}
const fileJson = new File([JSON.stringify(docJson)], "file.json", {type: "application/json'"});
const formData = new FormData();
formData.append('json', fileJson);
In the case you can't change backend and must create a file from client-side.
You can try this way:
const data = {someKey: 'value'};
const blob = new Blob([JSON.stringify(data)], {type: 'text/plain'});
const tmpFile = new File([blob], 'data_object_example.json');
// now you can pass this tmp file to a form with your pdf
const form = new FormData();
form.append('file', tmpFile);
Related
I want to send the recorded wecam video to django backend, But can't figure out how to generate the video in backend.
function sendVideoToAPI () {
const url = '/upload/'
let blob = new Blob(chunks, {type: media.type });
let fd = new FormData();
let file = new File([blob], 'recording');
fd.append('data', file);
fetch(url1, {
method: 'POST',
body: fd
})
.then(res => console.log(res))
.catch(err => console.log(err))
}
In django views how to generate the video
.Is there any way to do it..?
EDIT
Views.py
def upload(request):
if request.method == 'POST':
request.FILES.get('data') as f:
print(f.size)
print(type(f))
return redirect("/")
while running server it gives The following error
Error
request.FILES.get('data') as f:
^
SyntaxError: invalid syntax
in django's view you can access to your files through request like this:
request.FILES.get('data') as f:
# your code
NOTE: this will make you a 'TemporaryUploadedFile' which means that after working with that, it destroys automatically
I am sending a file like this to the server:
const fd = new FormData()
const targetFile = document.getElementById('default_file').files[0]
fd.append('file', targetFile )
fetch('url', {
method: 'POST',
body: fd,
})
I want to be able to encrypt the file with a password before uploading (client-side)
i have tried this so far but i'm not sure where to go next:
const targetFile = document.getElementById('default_file').files[0]
const reader = new FileReader()
reader.readAsArrayBuffer(targetFile)
reader.onload = () => {
console.log(reader.result)
const encrypted = CryptoJs.AES.encrypt(reader.result, "password123") <-- is this correct?
//should i convert the encrypted part to something specific?
}
reader.result returns the arraybuffer of the file, is it this part that i have to encrypt, and will the file stay in the same format so i can upload it to the server without changing code there?
I have an array of the object, each object contains some properties of type string and a file.
This is how my array looks like:
const args = [
{
name: 'presentation',
price: 9.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
},
{
name: 'presentation2',
price: 20.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
}
]
const headers = {
headers: {
Authorization: `Bearer ${token}`
}
};
My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3.
But Currently, I am unable to get the file stream on the server when I send this in a POST request,
even the whole req.body is an empty object when I console.log it
axios.post(`${slidesRoute}/createSlides`, args, headers);
Alternatively, I tried to put everything into FormData.
for example:
let formData = new FormData();
selectedFiles.forEach((selectedFile, i) => {
formData.append(`name_${i}`, selectedFile.name);
formData.append(`price_${i}`, selectedFile.price);
formData.append(`tags_${i}`, selectedFile.tags);
formData.append(`file_${i}`, selectedFile.file);
formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
});
axios.post(`${slidesRoute}/createSlides`, formData, headers);
Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like
file_1, file_2 file_3,...
But multer expects the exact filename to be passed
for example multer().array('file')
so in my second approach I am unable to catch files using Multer
You can't include file inside JSON. File is not JSON-serializable. Ideally you should have a separate endpoint to accept your files, send them with content-type: multipart/form-data, receive unique id for that file stored on the server, then send your JSON with ids instead of files.
As a chaper alternative you can Base64 encode your files into a string, insert this string in your request, and then decode it back on the receiving side
FormData key values are array by default
in your code Just change
formData.append(`file_${i}`, selectedFile.file);
to
formData.append(`file`, selectedFile.file);
You should be able to receive the file array in server side using multer().array('file')
Sample below demonstrating FormData key values array behavior
const formData = new FormData();
formData.append('key1', 'value1');
formData.append('key1', 'value2');
formData.append('key2', 'value1');
formData.forEach(function(value, key){
console.log(key, value);
});
I use FormData to send a number of files - and then on the node.js server I use Formidable.
I've pasted some partial code below that may help - sorry it's not a smaller sample.
Hope it helps
On the browser side I have:
let form_data = new FormData()
form_data.append('upload_data', file)
$.ajax({
url: '/file/upload' + remote_path + '/' + filename,
type: 'POST',
data: form_data,
processData: false,
contentType: false,
success: (res) => {
...
On the node.js side (apologies for the length..)I have:
const fs = require('fs')
const formidable = require('formidable')
const path = require('path')
...
app.post('/file/upload/*', (req, res) => {
let filename = req.params[0]
let media = path.basename(filename)
let folder = filename.substring(0, filename.length - media.length)
let form = new formidable.IncomingForm()
// form.encoding = 'utf-8'
form.multiples = true
form.uploadDir = path.join(media_folder, folder)
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
if (err) {
fail(res, 'failed to upload')
} else {
success(res)
}
})
form.on('fileBegin', (name, file) => {
const [fileName, fileExt] = file.name.split('.')
file.path = path.join(form.uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
})
form.on('file', (field, file) => {
fs.rename(file.path, path.join(form.uploadDir, file.name), (err) => {
if (!res.headersSent) { // Fix since first response is received
fail(res, 'an error has occured with form upload' + err)
}
})
})
form.on('error', (err) => {
fail(res, 'an error has occured with form upload' + err)
})
form.on('aborted', (err) => {
fail(res, 'Upload cancelled by browser')
})
})
The frontend of the application having a file download option (which can be in the following format: xlsx, csv, dat).
For that, I use fileSaver.js
Everything works fine for the format .dat/.csv but for the .xlsx it does not work the files are corrupted.
I tested the conversion with the following formats :
utf8
base64
binary
Here's how I do :
// /* BACK */ //
// data is
fs.readFile(filePath, (err, data) {...})
// the api give this answer the important part is "filename" & "data"
{"status":"ok","context":"writing the intermediate file","target":"/temp/","fileName":"name.xlsx","data":{"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]}}
// /* FRONT */ //
let json = JSON.stringify(data)
let buffer = Buffer.from(JSON.parse(json).data)
let read = buffer.toString('utf8')
let blob = new Blob([read])
FileSaver.saveAs(blob, fileName)
Ok for anybody who pass in this topic, my solution :
(keep in mind the real better solution for dl a file : send file in api response with header 'Content-disposition' or use express for that like this)
The back (Node) work like this :
fs.readFile(filePath, (err, data) => {
if (err) {
console.log(`-------- oups error - read --------`)
console.log(err)
res.send({ status: `erreur`, context: `read the source file`, id: err.errno, code: err.code, message: err.message.replace(/\\/g, '/') })
} else {
res.send({ status: `ok`, context: `send data file`, target: target, fileName: fileName, data: data })
}
})
Here :
target is the path for the front with the name of the file and his
extension (/path/name.ext)
fileName is juste the name and the extension (name.ext)
data is the data send by the readFile ({"type":"Buffer","data":[72,82,65,67,67,69,83,83,32,10]})
The front (React) work like this :
fetch(targetUrl)
.then(res => res.json())
.then(res => {
if (res.status !== `ok`) {
this.setState({
errorDlFile: true,
errorDlFile_context: res.context,
errorDlFile_id: res.id,
errorDlFile_code: res.code,
errorDlFile_message: res.message
})
} else {
const target = res.target
const fileName = res.fileName
const data = res.data
const splitName = res.fileName.split('.')
const format = splitName[splitName.length-1]
// file saver blob solution
let json = JSON.stringify(data)
let buffer = Buffer.from(JSON.parse(json).data)
let readUTF8 = buffer.toString('utf8')
let blob = ''
if (format === 'xlsx') {
blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
} else if (format === 'csv') {
blob = new Blob([readUTF8], { type: 'application/vnd.ms-excel' })
} else {
blob = new Blob([readUTF8])
}
FileSaver.saveAs(blob, fileName)
}
})
#Hadock
if you want to download file with .csv extension then you need to pass the type of file like
let blob = new Blob([csv], { type: 'application/vnd.ms-excel' });
instead of
let blob = new Blob([read])
and don't forgot to send filename with extension (test.csv).
For excel file I used different plugin exceljs demo.
you can't save json data directly to .xlsx file, you can convert json data to excel format using library like 'sheetjs' (https://sheetjs.com/)
var ws_name = filename;//"SheetJS";
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), filename + ".xlsx")
A form I use to upload a book cover to Cloudinary has an input type='file' on it. However I'd like to allow no image upload too that is when the form submits there is no file provided to input type='file'. Cloudinary responds with Request failed with status code 400.
This is how I try to mock a file to upload it to Cloudinary inside an action.
export const addBook = (bookData, history) => (dispatch) => {
const cloudinaryUrl = 'https://api.cloudinary.com/v1_1/*****/upload';
const cloudinaryUploadPreset = '*****';
const formData = new FormData();
bookData.cover[0] && formData.append('file', bookData.cover[0]);
if (!bookData.cover[0]) {
const blob = new Blob([''], { type: 'image/png' });
blob['lastModifiedDate'] = '';
blob['name'] = 'mockImageFile';
blob['webkitRelativePath'] = '';
blob['size'] = 7654;
formData.append('file', blob);
/* const f = new File([''], 'filename', { type: 'image/jpeg' });
formData.append('file', f); */
}
formData.append('upload_preset', cloudinaryUploadPreset);
axios({
url: cloudinaryUrl,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: formData
})
... ...
Still Cloudinary responds with Request failed with status code 400. How do I convince it to take a programmatically created 'file'?
The goal is to handle an upload with no file.
You need to convert blob data to a data URI which will be accepted by the file parameter to Cloudinary's upload method.
Please try below codebase to convert blob data to data URI. which you can append it to formdata.
const blob = new Blob([""],{ type: "image/png" });
blob["lastModifiedDate"] = "";
blob["name"] = "mockImageFile";
blob["webkitRelativePath"] = "";
blob["size"]=7654;
var reader = new FileReader();
var blob_base64data;
reader.readAsDataURL(blob);
reader.onloadend = function() { blob_base64data = reader.result;
};
formData.append("file", blob_base64data);
You can either perform a check for an empty file before uploading to Cloudinary and not upload to Cloudinary if there is no file or you can use a default image everytime there is no file uploaded instead of creating a blob.