Do I need to change the model below to upload images to django restapi?
function axmethod(url, method, options) {
if (options !== undefined) {
var {
params = {}, data = {}
} = options
} else {
params = data = {}
}
return new Promise((resolve, reject) => {
const config = {
}
axios({
url,
method,
params,
data,
}).then(res => {
resolve(res)
}, res => {
reject(res)
})
})
}
please help if I need to add?
I can see two things that might be the key:
In order to upload a image, you need to specify contentType: "multipart/form-data" in your config object
The uploaded data needs to be a FormData object. Let's say you have an object myCurrentData which contains a name string and the file itself. You can transform it using:
const data = new FormData();
Object.entries(myCurrentData).forEach(([key, value]) => data.append(key, value || ""));
Related
I'm trying to upload a base64 image from Angular to ExpressJS. I'm using html2canvas to create the base64 image. If I try and upload imageData in it's current form I get
imageData.replace is not a function. If I try stringifying it like this in angular service
const image = JSON.stringify(imageData);
const data = image.replace(/^data:image\/\w+;base64,/, '');
then I get Buffer is not a constructor
How can I get it to upload to ExpressJS server successfully? I appreciate any help!
component
ngAfterViewInit() {
sleep(5000).then(() => {
const table = document.getElementById('table');
this.dataUrl = html2canvas(table).then(function (canvas) {
const res = canvas.toDataURL();
return res;
});
this.angularService.uploadImage('png', this.dataUrl);
});
}
service
uploadImage(contentType, imageData) {
console.log("imageData", imageData)
const headers = new HttpHeaders();
if (contentType === 'jpeg') {
headers.set('Content-Type', 'image/jpeg;');
} else if (contentType === 'png') {
headers.set('Content-Type', 'image/jpeg;');
}
const data = imageData.replace(/^data:image\/\w+;base64,/, '');
const buff = new Buffer(imageData, 'base64');
return this.http.put(
environment.slsLocal + '/update-image-url',
buff.buffer,
{ headers: headers }
);
}
console.log('imageData', imageData) in service looks like this
You have 2 issues.
html2canvas(table).then returns promise. Not res. You have to call this.angularService inside html2canvas(table).then.
I am not sure what you are trying to do with const buff = new Buffer(imageData, 'base64');. If you want to upload the base64 contents, just put data.
Also please note that you have to subscribe the return of this.http.put because HTTP request will not thrown to your server unless it is subscribed.
Put it together.
component
ngAfterViewInit() {
sleep(5000).then(() => {
const table = document.getElementById('table');
html2canvas(table).then(function (canvas) {
const res = canvas.toDataURL();
this.dataUrl = res;
this.angularService.uploadImage('png', this.dataUrl)
.subscribe( result => {
// your logic
} );
});
});
}
service
uploadImage(contentType, imageData) {
console.log("imageData", imageData)
const headers = new HttpHeaders();
if (contentType === 'jpeg') {
headers.set('Content-Type', 'image/jpeg;');
} else if (contentType === 'png') {
headers.set('Content-Type', 'image/jpeg;');
}
const data = imageData.replace(/^data:image\/\w+;base64,/, '');
return this.http.put(
environment.slsLocal + '/update-image-url',
data,
{ headers: headers }
);
}
I try to upload file using Axios but I want to just use string of file path. Using code below it is working:
<input
id="select-files"
style="visibility: hidden"
type="file"
multiple
#change="handleFilesUpload($event)"
/>
But when I tried to use createReadStream it does not work. I wonder how I could convert these path files to event.target.files.
I already try the code above but it does not work:
let data = {
THE_FILE: "",
BRANCH_ID: this.$store.state.starv.localUser.DOCTOR_INFO["BRANCH_ID"],
ACC_NO: this.locationItem["ACC_NO"],
CHART_NO: this.locationItem["CHART_NO"],
EMP_ID: this.$store.state.starv.localUser.DOCTOR_INFO["EMP_ID"],
CO_EMP_ID: this.doctorList.toString(),
ST: "telehealthclient",
NEW_NAME: "",
MAID: LocalData.getComputerId(),
}
/*
Iterate over any file sent over appending the files to the form data.
*/
data["THE_FILE"] = window.fs.createReadStream(filePath)
let bodyFormData = new FormData()
// if (THE_FILE) {
// bodyFormData.append("THE_FILE", THE_FILE)
// }
for (let key in data) {
bodyFormData.append(key, data[key])
}
I already found the solution to this problem, what we would to do are below:
Encode our file to base64
base64_encode(file) {
// read binary data
let bitmap = window.fs.readFileSync(file);
// convert binary data to base64 encoded string
return new Buffer(bitmap).toString("base64");
},
Create a file-url object from our base64
dataURLtoFile(dataurl, filename) {
const arr = dataurl.split(",");
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n) {
u8arr[n - 1] = bstr.charCodeAt(n - 1);
n -= 1; // to make eslint happy
}
return new File([u8arr], filename, { type: mime });
},
Create form data from form-data library Upload using Axios
form-multipart
Full code is below
base64_encode(file) {
// read binary data
let bitmap = window.fs.readFileSync(file);
// convert binary data to base64 encoded string
return new Buffer(bitmap).toString("base64");
},
dataURLtoFile(dataurl, filename) {
const arr = dataurl.split(",");
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n) {
u8arr[n - 1] = bstr.charCodeAt(n - 1);
n -= 1; // to make eslint happy
}
return new File([u8arr], filename, { type: mime });
},
uploadScreenRecord(data) {
return new Promise((resolve, reject) => {
// #1 Convert to base64 first
let base64_video = this.base64_encode(data.file);
// #2 Create file url object from base64
let filename = path.parse(data.file).base;
let fileURLobject = this.dataURLtoFile(
"data:video/mp4;base64," + base64_video,
filename
);
// #3 Create form data from form-data libary
const formData = new formData_();
formData.append("THE_FILE", fileURLobject, filename);
for (let key in data) {
if (key != "file") {
formData.append(key, data[key]);
}
}
// #4 Send to server
let url;
if (SETTING.imedtacDomain.hostname == undefined) {
url = SETTING.webservice.imedtacProtocol + "//" + defaultDomain;
} else {
url =
SETTING.webservice.imedtacProtocol + "//" + SETTING.imedtacDomain.hostname;
}
axios
.post(url + SETTING.imedtacAPI.uploadFile.URL, formData, {
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "multipart/form-data",
},
timeout: 30000,
})
.then(function (response) {
//Return Patient
console.log("[File debug] This is upload file response %o", response);
if (response.data.success) {
resolve(response.data.FILE_URL);
} else {
reject(response.data.message + " screen record upload error");
}
})
.catch(function (error) {
reject(error);
});
});
},
submitFilesTest() {
return new Promise((resolve, reject) => {
//Data
let data = {
file: "/Users/ivanhutomo/Downloads/B0120221214151850_A.mp4",
BRANCH_ID: "xxx",
ACC_NO: "xx",
CHART_NO: "xx",
EMP_ID: "xx",
CO_EMP_ID: "xx",
ST: "xx",
NEW_NAME: "",
MAID: "xx",
};
this.uploadScreenRecord(data)
.then((response) => {
logger.debug("[File debug] File upload URL %o", response);
resolve(response);
})
.catch((error) => {
logger.debug("[File debug] File %o", error);
reject(error);
});
});
},
submitFilesTest()
Without getting response from const thumbnailSource = this.getThumbnailImage(); next line get excecuted, after getting response from getThumbnailImage() have to execute next line
constructor(private httpClient: HttpClient) {}
const defaultThumbnail: File[] = [];
const defaultArticle: File[] = [];
createArticle(articleData: IArticleData, thumbnail?: File | string, articleImage?: File | string) {
const defaultThumbnail: File[] = [];
const defaultArticle: File[] = [];
const formData = new FormData();
formData.append('title', articleData.title);
formData.append('author', articleData.author);
formData.append('articleData', articleData.articleData);
formData.append('published', JSON.stringify(articleData.published));
if (thumbnail) {
formData.append('thumbnail', thumbnail);
}
if (articleImage) {
formData.append('articleImage', articleImage);
}
if (!thumbnail) {
const thumbnailSource = this.getThumbnailImage();
thumbnailSource.subscribe((res) => {
defaultThumbnail.push(res);
});
formData.append('thumbnail', defaultThumail);
}
if (!articleImage) {
const articleSource = this.getArticleImage();
articleSource.subscribe((res) => {
defaultArticle.push(res);
});
formData.append('articleImage',defaultArticle);
}
formData.forEach((value, key) => {
console.log(key + ' ' + value);
});
return this.httpClient.post<IAPIResponse<IArticleCollection[]>>(`${baseUrl}/article/`, formData);
}
getThumbnailImage() {
return this.httpClient
.get('assets/images/logos/logo.png', {
responseType: 'arraybuffer',
})
.pipe(
map((response: any) => {
return new File([response], 'thumbnail-default.png', { type: 'image/png' });
}),
);
}
getArticleImage() {
return this.httpClient
.get('assets/images/logos/logo.png', {
responseType: 'arraybuffer',
})
.pipe(
map((response: any) => {
return new File([response], 'article-default.png', { type: 'image/png' });
}),
);
}
You return an observable that can depend of two observables or not, so you can use the Rxjs operators
of: return an objservable of a value, e.g. of(1) return an
Observable
forkJoin: return an observable compouned from others observables
switchmap: transform an observable in another observable (it's used
when the "inner" observable depend from the outer observable
//you create two observables
const thumbnailSource = thumbnail? of(thumbnail):this.getThumbnailImage();
const articleSource = articleImage? of (articleImage) : this.getArticleImage();
//you create an unique observable using forkJoin
return forkJoin([thumbnailSource,articleSource]).pipe(
switchMap(([thumbnail,articleImage])=>
{
const formData = new FormData();
formData.append('title', articleData.title);
formData.append('author', articleData.author);
formData.append('articleData', articleData.articleData);
formData.append('published', JSON.stringify(articleData.published));
formData.append('thumbnail', thumbnail);
formData.append('articleImage',articleImage);
return this.httpClient.post<IAPIResponse<IArticleCollection[]>>
(`${baseUrl}/article/`, formData);
}
))
BTW, is unneccesary use formData, you can use a simple object
return forkJoin([thumbnailSource,articleSource]).pipe(
switchMap(([thumbnail,articleImage])=>
{
const data={
'title', articleData.title,
'author', articleData.author,
'articleData', articleData.articleData,
'published', JSON.stringify(articleData.published),
'thumbnail', thumbnail,
'articleImage',articleImage
}
return this.httpClient.post<IAPIResponse<IArticleCollection[]>>
(`${baseUrl}/article/`, data);
}
))
I'm using VueJS and Cypress. I have a modal where I submit a FormData with different filled and a file:
var formData = new FormData();
formData.append("document_file", this.documentFile);
formData.append("comments", this.comments.value);
...
They way I upload it:
this.$http.post('http://localhost:8081/api/upload',formData,{emulateJSON: true},{
header:{ "Content-Type":"multipart/form-data" },
}).then(function(response) {
// ... Code
}).catch((err) => {
// .. Code
});
}
I want to use Cypress to test the params. Now, when I don't use the document file in the formData, I have the following methods to parse the multipart/form-data; boundary=---:
function parse(request) {
console.log("request");
console.log(request);
const headers = request.headers;
const body = request.body;
const content_type = headers['content-type'];
expect(content_type, 'boundary').to.match(/^multipart\/form-data; boundary=/);
const boundary = content_type.split('boundary=')[1];
const values = p(boundary, body);
return values;
}
function p(boundary, body) {
expect(boundary, 'boundary').to.be.a('string');
expect(body, 'body').to.be.a('string');
const parts = body.split(`--${boundary}`).map((s) => s.trim()).filter((s) => s.startsWith('Content-Disposition: form-data;'));
const result = {};
parts.forEach((part) => {
const lines = part.split(/\r?\n/g);
const key = lines[0].match(/name="(.+)"/)[1];
result[key] = (lines.length >= 2) ? lines[2].trim() : "";
});
return result;
}
Which work great. But when I upload the file, I get a different request.body:
They way I'm trying to test:
cy.get('#createDocument').then((interception) => {
assert.isNotNull(interception);
const values = parse(interception.request);
assert.isTrue(values.comments === "");
});
How can I handle this?
I am trying to upload an array of images using my custom API (Node JavaScript), here I just want to save the file name to my database, and uploading of the file works just fine (the middleware which I created for uploading works just fine because I have tried using the same middleware in the postman).
When it comes to the actual JavaScript file it is not working and shows the following error:
Cast to string failed for value "{ '0': {}, '1': {} }" at path "images", images: Cast to Array failed for value "[ { '0': {}, '1': {} } ]" at path "images"
Here is my code
const createProperty = ['city', 'propertyType', 'propertyName', 'images'];
const newProperty = new Array();
for (var i = 0; i < myids.length; i++) {
newProperty[i] = $(myids[i]).val();
}
newProperty[myids.length] = [document.getElementById('PropertyPhotos').files];
const data = {};
createProperty.forEach((id, index) => {
data[createProperty[index]] = newProperty[index]
})
await createData(data);
// here is the CreateDate function
export const createData = async (data) => {
try {
const res = await axios({
method: 'POST',
url: '/api/v1/properties',
data
});
if (res.data.status === 'success') {
showAlert('success', 'Property Created Successfully');
}
console.log(res.data);
} catch (err) {
showAlert('error', err.response.data.message);
console.log(err.response.data.message);
}
}
It looks like you are using Mongo. Look here and here.
And to send files you need to use form-data, but I don't see it in your code.
const formdata = new FormData();
formdata.append("file", fileInput.files[0], "/filepath.pdf");