Post multipart/form-data to endpoint - excel

I'm trying to create an upload form for excel files with angular 6. I have implemented a file chooser with which i want to upload (post) excel files to a certain endpoint that expects "MULTIPART_FORM_DATA". Now i have read that you should not set the content type in the header for angular versions above 5 but if i do not include the content-type in the header the angular application automatically sets it to
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", which the server does not expect and hence results in a "bad request". So how can i implement a valid "post" for multipart/form-data with angular 6?
the endpoint looks something like this:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadExcel(
#FormDataParam("file") InputStream inputStream,
#FormDataParam("file") FormDataContentDisposition contentDispositionHeader){...}
the angular component looks something like this:
handleFileInput(event: any): void {
if (!event.target.files.length) {
return;
}
this.fileToUpload = event.target.files.item(0);}
private uploadFile(): void {
this.fileService.uploadFile(this.fileToUpload).subscribe(
(res: any) => {
console.log('upload succeeded');
}
);}
the html form looks something like this:
<form (submit)="uploadFile()" enctype="multipart/form-data">
<label for="file">choose excel file to upload: </label>
<input type="file" name="file" id="file" accept=".xls,.xlsx" (change)="handleFileInput($event)">
<input type="submit" name="submit" class="submitButton">
and the service looks like this:
uploadFile(file: File): Observable<any> {
const fd: FormData = new FormData();
fd.append('file', file, file.name);
return this.http.post(this.fileURL, file);
}

I found the mistake I've made: I passed the wrong argument to the http.post call.
The service should of course look like this:
uploadFile(file: File): Observable<any> {
const fd: FormData = new FormData();
fd.append('file', file, file.name);
return this.http.post(this.fileURL, fd);
}

Related

How to send data from react.js to node?

I am a beginner in web devolopment and I'm developing an application using react and nodejs. I've been looking for ways to send the data from front end i.e, react(data received from the user) to nodejs code so that I can process it and send it back to the UI. I saw some resources mentioning that I can use fetch and axios but I can't quite follow it. So basically my application is about executing the pipe commands of linux. There will be few buttons to choose which command to execute(Like sort, uniq etc). There will be a text area to get the input text and a label to display the output. So how can I send the input data to the nodejs function so that I can process it with some built-in modules and return the output to the label.My code for text area looks like this
import { useState } from "react";
const Text_area = () =>{
const[text,setText] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
const data = {text};
}
return(
<>
<form onSubmit={handleSubmit}>
<label>Input here</label>
<textarea value= {text} required onChange={(e)=>setText(e.target.value)}/>
<button>OK</button>
</form>
</>
);
}
Share your thoughts please!
I assume you have only index route, that's why fetch is pointing to index.
const[text,setText] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
const newText= { text };
fetch("/", {
method: "POST",
headers: {"Content-Type": "application/JSON"},
body: JSON.stringify(newText)
})
}
Above, fetch method is used to send your data to relevant route in your node.js file.
And in your server.js file, you can code something like this to see if it works:
app.post("/", function(req, res){
res.send(req.body);
});
Please let me know if it works for you.
Think of your problem like a Form HTML element. How can a form send data to server?
Basically, they use HTTP GET/POST method. If you don't know it, Google! But for now, let just understand that: To send data from react.js to node, you need do something with HTTP GET/POST method.
<form action="/send_form" method="post">
<input type="text" id="fname" name="fname">
<input type="text" id="lname" name="lname">
<input type="submit" value="Submit">
</form>
form element has done it for you. This is why you see people mentioned axios because what if I don't use form? How can I do the same thing without form?
Then how do server receive information? You will do that by code something in Node.js. Googled yourself :>.
Then people mentioned Express.js. Think of it as "React" of Node.js, which mean it's a framework. You don't need to know "Express.js" to receive information sent from React.

Why is my image file being converted to a string?

Edit, original question has been resolved as to why file was converted to string. The code has been edited to reflect these corrections. The API handler is now outputting object as data type and buffer as the value of request.payload.file.
I'm using Aurelia to make a Single Page App. There is a HTML form that accepts two input fields, one for a file, one for text. These fields are bound to variables (selecetdImage and title) in an associated TypeScript view model. In the viewmodel they are used as arguments in a function that appends them to formData and sends a http post request with the formData to an Node/js Hapi framework API handler.
When I console.log(typeof(selectedImage) in the Aurelia app, it states object, but when I console log typeOf(selecetdImage) in the handler, I get String. I'm guessing this is why my function isn't working and giving 500 error messages
The handler itself works. I used it in a MVC server based web app. In that context, HTML form triggers a post request, and the MVC handler successfully receives the file, writes it to local/temp.img and uploads it to cloudinary.
But with the API version, where I assembled the form data myself as above, the file isn't written to local/temp.img and the cloudinary upload fails.
Edit.
I changed the viewmodel variables to
title = null;
files = null;
and I changed the formData append function to:
formData.append('file', File, files[0]);
As per the example here. The code below is now modified to match this update.
Now when I console log the value of file in the API handler, the output is:
<Buffer ff d8 ff e0 00 10.......
I'm not sure what to do with this data. I assume it's the image binary data in octal? And if so, does anyone know how to write it as an image in node?
The payload is no longer of type string, now it's type object.
<form submit.delegate="uploadPhoto()" enctype="multipart/form-data">
<div class="two fields">
<div class="field">
<label>File</label>
<input type="file" name="file" accept="image/png, image/jpeg" files.bind="files">
</div>
<div class="field">
<label>Title</label> <input value.bind="title">
</div>
</div>
<button type="submit"> Upload </button>
</form>
//photoUpload.ts// (view model associated with above html
#inject(POIService)
export class PhotoForm {
#bindable
photos: Photo[];
title = null;
files = null;
constructor (private poi: POIService) {}
uploadPhoto() {
const result = this.poi.uploadPhoto(this.title, this.files);
console.log(this.title);
console.log(result);
}
//POIService (where contains injected function to create HTTP request
async uploadPhoto(title: string, files){
console.log("now uploading photo for: " + this.currentLocation)
let formData = new FormData();
formData.append("title", title);
formData.append("location", this.currentLocation); //don't worry about this variable, it's set by another function every time a page is viewed
formData.append("file", files[0]);
const response = await this.httpClient.post('/api/locations/' + this.currentLocation + '/photos', formData);
console.log(response);
}
//API Handler (accepts HTTP request, writes the image to a local folder, the uploads to cloudinary and returns the url and photo_id which are stored in a Mongod document
create: {
auth: false,
handler: async function(request, h) {
const photo = request.payload.file;
await writeFile('./public/temp.img', photo);
const result = await cloudinary.v2.uploader.upload('./public/temp.img', function(error, result) {
console.log(result)
});
const newPhoto = new Photo({
title: request.payload.title,
url: result.url,
public_id: result.public_id,
location: request.params.name
})
await newPhoto.save();
return newPhoto;
}
},
Is it a very long string, containing "data:b64" in the first 15 or so characters? If so, that means it's the base64 data.

Calling post api with file in the body

I want to call a rest API which takes an image as input. But I am not able to pass the file. We can send the URL of the image as an input to the API. Following is the body format.
{ 'url': 'String URL of the Image'}
When I call the same API from the postman it works fine. But not able to understand how can we call it from the nodeJS.
If any one could help me in that.
Thanks & Best Regards,
Sagar
Use axios package to send your POST request here is an exemple :
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('URL_TO_API', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
HTML
<form id="uploadForm" role="form" method="post" enctype=multipart/form-data>
<input type="file" id="file" name="file">
<input type=submit value=Upload>
</form>

Grab file from chrome webRequest onBeforeRequest

I am trying to fetch the files that want to be uploaded via POST.
Unfortunately i only get the requestBody as FormData giving me huge headaches accessing the file. I only get the filename as string.... I would like to have the file contents as blob or data-url...
//in a form on a page
<input type="file" name="files[]" multiple>
//extension's background.js
chrome.webRequest.onBeforeRequest.addListener( function(details) {
console.log(details);
n = "files[]";
var file = details.requestBody.formData[n][0];
console.log(file ); // BabyGnuTux-Big.jpg
console.log(typeof file); // string
},
{urls: ["*://example.de/*"]},
["blocking", "requestBody"]);

How to upload a file (attachment) from the browser?

I don't get attachment upload for the browser to work.
Some hints are here, others there. The docs are quite good but I'm unable to translate that to a AJAX upload.
I'm looking for a super simple HTML/JavaScript example (with or w/o jQuery) of how to upload a file from (relatively modern) browser to the db without making use of jquery.couch.app.js wrapper or stuff. The simpler the besser.
Any help appreciated.
Alright, here's your pure JavaScript file upload implementation.
The basic algorithm is like this:
Get the file from the file input element
Get the file name and type off the file object
Get the latest document revision of the document you want to attach the file to
Attach the file to document using the fetched revision
The HTML part basically consists of a simple form with two elements, an input of type file and a button of type submit.
<form action="/" method="post" name="upload">
<input type="file" name="file" />
<button type="submit" name="submit">Upload</button>
</form>
Now to the JavaScript part.
window.onload = function() {
var app = function() {
var baseUrl = 'http://127.0.0.1:5984/playground/';
var fileInput = document.forms['upload'].elements['file'];
document.forms['upload'].onsubmit = function() {
uploadFile('foo', fileInput.files[0]);
return false;
};
var uploadFile = function(docName, file) {
var name = encodeURIComponent(file.name),
type = file.type,
fileReader = new FileReader(),
getRequest = new XMLHttpRequest(),
putRequest = new XMLHttpRequest();
getRequest.open('GET', baseUrl + encodeURIComponent(docName),
true);
getRequest.send();
getRequest.onreadystatechange = function(response) {
if (getRequest.readyState == 4 && getRequest.status == 200) {
var doc = JSON.parse(getRequest.responseText);
putRequest.open('PUT', baseUrl +
encodeURIComponent(docName) + '/' +
name + '?rev=' + doc._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent.target.result);
};
putRequest.onreadystatechange = function(response) {
if (putRequest.readyState == 4) {
console.log(putRequest);
}
};
}
};
};
};
app();
};
Basically, I intercept the submit event of the form by binding my own function to the form's onsubmit event and returning false.
In that event handler I call my main function with two parameters. The first one being the document name and the second one being the file to upload.
In my uploadFile() function I set the file name, file type and grab some instances. The first HTTP request is a GET request to obtain the current revision of the document. If that request succeeds I prepare the PUT request (the actual upload request) by setting the previously obtained revision, the proper content type and then I convert the file to an ArrayBuffer. Once that's done I just send the HTTP request I've just prepared and then I relax.
The standalone attachment upload scheme looks like this:
PUT host/database/document/filename?revision=latest-revision
Of course using the proper content type in the HTTP request header.
Note: I'm well aware that I'm not making use of defensive programming here at all, I did that deliberately for brevity.

Resources