How to use fetch to upload files to web api(parameter problem) - javascript

My aspnetcore web api side is
[ApiController]
[Route("api/[controller]")]
public class SoundController : ControllerBase
{
[HttpPost]
public async Task<IActionResult> OnPostUploadAsync(List<IFormFile> files0)
{
var files = Request.Form.Files;
.....
return Ok(new { count = files.Count, size });
}
}
My script to post file is as follows:
const blob = new Blob(chunks, { type: "audio/mp3" });
let formData = new FormData();
formData.append("abcd", blob, "a.mp3");
let response = await fetch("api/sound", {
method: 'post',
body: formData
});
if (response.ok) {
var data = await response.json();
console.log(`response.status=${response.status}, data.count==${data.count},
data.size=${data.size}`);
}
My question is:
Although fetch DO reach the OnPostUploadAsync function,
but the parameter files0 is of length 0.
hower inside OnPostUploadAsync function, we can use Request.Form.Files to get the file uploaded by fetch.
what am I wrong? parameter type issue?

Related

Upload and pin image with Piniata api on client side, no nodejs

I am trying to use the Piniata api. Here it is:
https://docs.pinata.cloud/
The idea is to upload and pin and image using the api, into my account in Piniata.
I got this sample to upload a file in base64, using Node.js and server side.
The sample use this api call:
"https://api.pinata.cloud/pinning/pinFileToIPFS"
I am suppose to be able to do this in client side as well.
However, there is no sample of client side without using Node.js. And I can't seem to find exactly a documentation of what the api call expects.
Here is the sample I got from the Piniata support:
const { Readable } = require("stream");
const FormData = require("form-data");
const axios = require("axios");
(async () => {
try {
const base64 = "BASE64 FILE STRING";
const imgBuffer = Buffer.from(base64, "base64");
const stream = Readable.from(imgBuffer);
const data = new FormData();
data.append('file', stream, {
filepath: 'FILENAME.png'
})
const res = await axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", data, {
maxBodyLength: "Infinity",
headers: {
'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
pinata_api_key: pinataApiKey,
pinata_secret_api_key: pinataSecretApiKey
}
});
console.log(res.data);
} catch (error) {
console.log(error);
}
})();
Here is my attempt to perform an upload from client side without Node.js
async function uploadFile(base64Data)
{
const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`;
var status = 0;
try {
let data = new FormData();
var fileName = "FILENAME.png";
var file = new File([base64Data], fileName, {type: "image/png+base64"});
data.append(`data`, file, file.name);
data.append(`maxBodyLength`, "Infinity");
const response = await postData('POST', url, {
'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
"Authorization": "Bearer Redacted"
},
data
);
} catch (error) {
console.log('error');
console.log(error);
}
}
What I get as a response from the server is 400 and the error being:
{"error":"Invalid request format."}
What am I doing wrong?
Also, it seems like when I try to use FormData .append with a stream as a sample, it doesn't work. As if it only expects a blob.

Send file to (fetch to c# web api)

I tried to send file by JS Fetxh API to ASP .NET 6 WebAPI and get 400 status.
let data = new FormData()
data.append('file', file)
const response = await fetch('https://localhost:7054/Pictures',
{
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
body: data
});
[HttpPost]
public async Task<ActionResult> Index([FromBody]IFormFile file)
{
try
{
using (var fs = new FileStream(dir, FileMode.Create))
{
await file.CopyToAsync(fs);
}
return StatusCode(StatusCodes.Status201Created);
}
catch
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
If delete FormData and send 'file' get the same error.
If delete 'Content-Type' get 415 status in every case.
If set 'Content-Type' to 'application/json' and IFormFile change to string, then send json it works ok.
1.[FromBody] is used receive application/json data. You need change [FromBody] to [FromForm]
2.To upload files using fetch and FormData.you must not set Content-Type header.
Whole working demo below:
let data = new FormData();
data.append('file', file);
const response = fetch('https://localhost:7054/Pictures',
{
method: 'POST',
body: data
});
Api controller:
[HttpPost]
public async Task<ActionResult> Index([FromForm] IFormFile file)
{
//.....
}

How to convert a readable stream to a blob in javascript?

I have a test that should read a image file and submit the image file to an api that accepts a multipart-formdata.
I am using the fetch api along with formdata class to set the image file. The formdata only accepts a blob. So in my test i must convert the the file i read in which is of type stream to a blob.
test("should submit front document", async () => {
const side = "front";
const stream = fs.createReadStream(process.cwd() + "/test/resources/" + "id/front.jpg");
const image = await streamToBlob(stream);
const front = await myLibrary.document(id, side, image);
expect(front.success).toBe(true);
});
I am attempting to use a library here to convert the stream to a blob https://www.npmjs.com/package/stream-to-blob. However the test is failing. If i attempt to console.log(image) i get the following Blob {}
Why is the blob empty {}?
async document(id, side, image) {
const url = this.API_URL + "/document"
let formData = new FormData();
formData.set("image", image, "front.jpg");
formData.set("side", side);
let headers = new Headers();
headers.set("Authorization", "Bearer " + this.API_KEY);
const request = {
method: "POST",
body: formData,
headers: headers,
};
try {
const response = await fetch(url, request);
const data = await response.json();
return data;
} catch (err) {
throw err;
}
}

Send Image file along with other data to Java backend using React.JS

I want to send an uploaded image file along with data entered by the user to the backend which is implemented on JAVA.
`const payload = {
id: null,
name : Name,
email : Email
};
//data.append("myjsonkey", );
await fetch('http://localhost:8080/student/insertStudent', {
method: 'POST',
body: JSON.stringify(payload),
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})`
Using this implementation I was able to send data to backend using POST request. I now want to attach an image file in the payload to be recieved at the backend.
The Code written for the image uploading is
`fileChangedHandler = (event) => {
this.setState({selectedFile: event.target.files[0]})
}
uploadHandler = () => {
console.log(this.state.selectedFile)
}
render() {
return (
<div>
<input type="file" onChange={this.fileChangedHandler}/>
<button onClick={this.uploadHandler}>Upload!</button>
</div>
);
}`
Any help will be highly appreciated.
You can send data using formData... here is the sample code for api request in react.
uploadHandler = () => {
const formData = new FormData();
formData.append('file', this.state.selectedFile);
axios.post('http://localhost:8080/student/image',
formData
);
}
Java controller
#CrossOrigin(origins = "http://localhost:3000")
#RestController
#RequestMapping("/student/")
public class StudentController {
#RequestMapping(value = "image" ,method = RequestMethod.POST, consumes = "multipart/form-data")
#ResponseStatus(HttpStatus.CREATED)
public void image(
#RequestParam("file") MultipartFile file ){
// CODE HERE
}
}

Http failure during parsing Angular 5

Receiving HTTP Failure during parsing in Angular. Goal is to download a csv file from the api response
Controller:
downloadFile(data) {
const blob = new Blob([data], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
window.open(url);
}
getFileDownload(): void {
this.iportalUploadService.getFileDownload(this.fileName).subscribe(data => {
debugger;
this.fileDownload = data;
this.downloadFile(data);
});
}
Service:
private fileDownloadUrl = 'file-transfer/validationErrorsCSV';
formHtppOptions(params): any {
const httpOptions = {
headers: { 'Application-Token': this.getToken() },
params: params,
};
return httpOptions;
}
getFileDownload(fileName): Observable < Object > {
const baseUrl = this.getBaseUrl();
return this.http.get<Object>(baseUrl + this.fileDownloadUrl, this.formHtppOptions({ fileName: fileName }));
}
Below is the console error I am receiving
console error
Response format Photo
Response photo
You are getting this error because your response is not in JSON format. You are trying to convert it into an object and CSV text cannot be parsed to a proper json object. Here is what you might want to do:
getFileDownload(fileName): Observable<any> {
const baseUrl = this.getBaseUrl();
return this.http.get(baseUrl + this.fileDownloadUrl, this.formHtppOptions({fileName: fileName})).pipe(map((data:any) => this.converter.ToJson(data)));
}
Usually, I have a "converter" service that does this kind of parsing. You can make use of papa parse, or parse yourself by looping through the response.
Update: Here is an example of manually parsing the response: http://blog.sodhanalibrary.com/2016/10/read-csv-data-using-angular-2.html
Have a look at the above blog post.
I resolved this issue by adding responseType: 'text' in formhttpOtions.

Categories