Sending Audio Blob data from a React frontend to a Express backend - node.js

so I am running into an issue with sending audio(created in the browser) to my backend to be stored in a database. I am using React on the Front-end and using the Web Audio API to allow a user to create audio. When I send it, the backend just receives an empty object. Does anyone know how I can get the data to persist so that it can be stored in the database to be played later?
mediaRecorderOnStop() {
console.log("data available after MediaRecorder.stop() called.");
const clipName = prompt('Enter a name for your sound clip?', 'My unnamed clip')
//creating new blob object
const blob = new Blob(this.state.chunks, { 'type': 'audio/ogg; codecs=opus' });
//sending data to the backend
uploadDocumentRequest(this.props.createClip(blob, clipName))
this.setState({
chunks: []
})
console.log("recorder stopped");
}
//makes a api post request to server
export function uploadDocumentRequest(data) {
axios.post('/api/createAudio', data)
.then(response => console.log(uploadSuccess(response)))
.catch(error => console.log(uploadFail(error)));
}
Here is an image of my code

assuming you are sending JSON, you won't be able to send a binary data to the server.
you have to encode you data with multipart/formdata
for that you should construct FormData object which later can be sent via XHR or Fetch API
var fd = new FormData();
var fd.append('audio', blob);
fetch(apiUrl + '/api/createAudio', {
headers: { Accept: "application/json" },
method: "POST", body: fd
});
the request Content-Type: multipart/formdata header will be automatically set
you have to make sure that you web app is able to process multipart/formadata encoded requests

Related

How can I use Axios to access the JSON data within a response sent using Expressjs?

I'm creating a web application that generates a pdf on a server then sends it to the client for display within the browser.
The client is using Vuejs / Axios to send a POST request. Afterwards, The server is receiving it with Expressjs, generating a unique PDF, converting the file to a base64 value then sending it back as a response.
I cannot seem to get the response correct. When I attempt to display response.data.pdfData within the client I get undefined in the console. I can see that there is indeed a response with the key and value pair using inspection tools within the Network tab under the Preview section but cannot seem to access it.
// FILE: ./Client/src/App.vue
submit(personalInfo) {
this.cardInfo.personalInfo = personalInfo;
console.log('Sending POST preview_card...');
axios({
url: 'http://localhost:5000/api/preview_card',
method: 'POST',
responseType: 'blob',
data: {
cardInfo: this.cardInfo,
},
}).then((response) => {
console.log(response.data.pdfData);
});
},
// FILE: ./Server/app.js
app.post('/api/preview_card', (req, res) => {
// Generate pdf
const doc = new jsPDF('p');
doc.setFontSize(40);
doc.text(req.body.cardInfo.templateInfo, 100, 100);
doc.save('response.pdf');
// Convert pdf to base64
var tempFile = path.resolve(__dirname, './response.pdf');
var pdfBase64 = fs.readFileSync(tempFile).toString('base64');
res.setHeader('Content-Type', 'application/json');
return res.send(JSON.stringify({ pdfData: pdfBase64 }));
});
I find it necessary to serve the pdf this way due to my client's compnents as well as to enforce a level of data coherency between concurrent users.

Sending FormData through 2 API's (NextJS)

So I'm sending some formdata, including images to my backend. To obfuscate/secure my backend even more - I'm learning that it's good practice to take advantage of the NextJS api (send calls from client to NextJS server/api, NextJS api acts as a middleman and sends data to backend api). I'm also using Auth0 - and the most secure way to get tokens is via the NextJS api itself.
I have no issues reading the data on my backend when I make an api call directly from client to backend. However, I'm having issues actually getting the data (primarily the images/files) OUT of the request on my NextJS api for repackaging and sending to my actual backend. I can't use FormData within the NextJS api either, so I'm just confused all around.
Client submit function:
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("title", brand.name);
formData.append("slug", brand.slug);
formData.append("bio", brand.bio);
formData.append("logo", brand.logo[0]);
const response = await fetch("/api/brands", {
method: "post",
body: formData,
});
});
NextJS api code (does not work - I am getting an access token perfectly, it's just the sending of the formdata/files I'm stuck on)
import { getAccessToken, withApiAuthRequired } from "#auth0/nextjs-auth0";
export default withApiAuthRequired(async function products(req, res) {
const { accessToken } = await getAccessToken(req, res, {});
const response = await fetch("http://localhost:5000/brands", {
method: "post",
headers: {
Authorization: `Bearer ${accessToken}`,
},
body: {
title: req.body.title,
slug: req.body.slug,
bio: req.body.bio,
logo: req.file,
},
});
const products = await response.json();
res.status(200);
});
You might be missing the "Content-Type: multipart/form-data" on the 2nd API call that you make. On the client side it's inferred from the FormData object, but on the server side you have to specify it manually. Altough, I couldn't find a way to do that on the server. This could indicate that the use case is wrong, I think making another request to your own server is a no-no. Next.js is meant to use this function called "withApiAuthRequired" as a wrapper, from which you call your services, or business logic. There is no need to make a second HTTP Request here.

How can I send post request with base64 image?

I am making an image upload component in vue js with custom cropping option. The cropped version is being saved in my state as a base64 string. This is it:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAYAAAB91L6VAAAgAElEQVR4Xu2dCdh+1dT/v3+UDA1KMiQhlCEylDGZSqbI0Jy8JMmYUEloRFIpVJK5EpL0ilJmr6IQKiXzrCKESP2v72vfb8/z/O7hnH2fc/be53z2df2uoj1+9vrd6+y1117r/4kCAQhAAAIQgEDnBP5f5yMyIAQgAAEIQAACQgEjBBCAAAQgAIEEBFDACaAzJAQgAAEIQAAFjAxAAAIQgAAEEhBAASeAzpAQgAAEIAABFDAyAAEIQAACEEhAAAWcADpDQgACEIAABFDAyAAEIAABCEAgAQEUcALoDAkBCEAAAhBAASMDEIAABCAAgQQEUMAJoDMkBCAAAQhAAAWMDEAAAhCAAAQSEEABJ4DOkBCAAAQgAAEUMDIAAQhAAAIQSEAABZwAOkNCAAIQgAAEUMDIAAQgAAEIQCABARRwAugMCQEIQAACEEABIwMQgAAEIACBBARQwAmgMyQEIAABCEAABYwMQAACEIAABBIQQAEngM6QEIAABCAAARQwMgABCEAAAhBIQAAFnAA6Q0IAAhCAAARQwMgABCAAAQhAIAEBFHAC6AwJAQhAAAIQQAEjAxCAAAQgAIEEBFDACaAzJAQgAAEIQAAFjAxAAAIQgAAEEhBAASeAzpAQgAAEIAABFDAyAAEIQAACEEhAAAWcADpDQgACEIAABFDAyAAEIAABCEAgAQEUcALoDAkBCEAAAhBAASMDEIAABCAAgQQEUMAJoDMkBCAAAQhAAA....
now I am trying to send this image to my node js server using post request API. In Postman, I am writing the body selecting "raw" and "json" in this the body in this way:
{
"image" : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAYAAAB91L6VAAAgAElEQVR4Xu2dCdh+1dT/v3+UDA1KMiQhlCEylDGZSqbI0Jy8JMmYUEloRFIpVJK5EpL0ilJmr6IQKiXzrCKESP2v72vfb8/z/O7hnH2fc/be53z2df2uoj1+9vrd6+y1117r/4kCAQhAAAIQgEDnBP5f5yMyIAQgAAEIQAACQgEjBBCAAAQgAIEEBFDACaAzJAQgAAEIQAAFjAxAAAIQgAAEEhBAASeAzpAQgAAEIAABFDAyAAEIQAACEEhAAAWcADpDQgACEIAABFDAyAAEIAABCEAgAQEUcALoDAkBCEAAAhBAASMDEIAABCAAgQQEUMAJoDMkBCAAAQhAAAWMDEAAAhCAAAQSEEABJ4DOkBCAAAQgAAEUMDIAAQhAAAIQSEAABZwAOkNCAAIQgAAEUMDIAAQgAAEIQCABARRwAugMCQEIQAACEEABIwMQgAAEIACBBARQwAmgMyQEIAABCEAABYwMQAACEIAABBIQQAEngM6QEIAABCAAARQwMgABCEAAAhBIQAAFnAA6Q0IAAhCAAARQwMgABCAAAQhAIAEBFHAC6AwJAQhAAAIQQAEjAxCAAAQgAIEEBFDACaAzJAQgAAEIQAAFjAxAAAIQgAAEEhBAASeAzpAQgAAEIAABFDAyAAEIQAACEEhAAAWcADpDQgACEIAABFDAyAAEIAABCEAgAQEUcALoDAkBCEAAAhBAASMDEIAABCAAgQQEUMAJoDMkBCAAAQhAAAWMDEAAAhCAAAQSEEABJ4DOkBCAAAQgAAEUMDIAAQhAAAIQSEAABZwAOkNCAAIQgAAEUMDIAAQgAAEIQCABARRwAugMCQEIQAACEEABIwMQgAAEIACBBARQwAmgMyQEIAABCEAABYwMQAACEIAABBIQQAEngM6QEIAABCAAARQwMgABCEAAAhBIQAAFnAA6Q0IAAhCAAARQwMgABCAAAQhAIAEBFHAC6AwJAQhAAAIQQAEjAxCA.....
}
The request not detecting this json data in the body and returning error:
{
"image": "\"image\" is required"
}
Also tried the form_data sending method in this way:
var axios = require('axios');
var FormData = require('form-data');
// var fs = require('fs');
var data = new FormData();
data.append('image', formdata.logoFinalImage);
var config = {
method: 'post',
url: myurl,
headers: {
'Authorization': this.state.token,
'Content-Type': 'application/json'
},
data: data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Same issue.
How can I send the final cropped version to the node api endpoint?
Solved the issue. There were two ways of doing it. One is required changes in the backend to configure the code in a way that can receive base64 and convert it to image. Reference: https://medium.com/js-dojo/how-to-upload-base64-images-in-vue-nodejs-4e89635daebc
Other is to make the base64 image file, and then send it to the backend as form-data. Used this one for my case. Reference of this solution: https://gist.github.com/ibreathebsb/a104a9297d5df4c8ae944a4ed149bcf1
if its working in postman then you can create the code from postman itself , select code and search for axios
v8<
if using v8

Node, Multer & Axios : Sending a media to server

I am struggling with a simple media (mp3/mp4) upload to a server using axios.
I have an angular application that creates a formData and send this formData to node server via :
return this.http.post(this.apiURL + '/uploadFile', formData);
My server method looks like this :
app.post('/api/uploadFile', upload.single('file'), (req, res) => {
inputFile = req.file;
let fd = new FormData();
fd.append('file',inputFile.buffer, inputFile.originalname);
axios.post(uploadFileURL , fd, { headers: { 'Content-Type': 'multipart/form-data' } })
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error)
})
})
The inputFile contains the original files. The error I get now is that the request is not a multipart request...
I tried as well to define the formData differently :
formData = {
file: {
value: inputFile.buffer,
options: {
filename: inputFile.originalname,
contentType: inputFile.mimetype
}
}
};
Which brought me to a different error : 'Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found'
Am I doing something wrong ?
I am wondering if this could be link to the fact that I use const bodyParser = require('body-parser'); for some of my other requests.
Any help would be appreciated!
Thanks
EDIT :
Here is my need and what I've done so far :
I have a web application that allow users to upload media files.
I have to send those files to a server, but I can not use the browser to send the request directly.
I created a nodejs application to realize the proxy task of getting the files from the browser and sending it to my remote server.

axios multipart request failing

Im trying to send a post request for convert doc to pdf using a service. The service is working fine with postman, y can send the doc to the endpoint and it return me the pdf, nice.
But i cant make the request from my nodejs server, im using axios to make the request and it fails with this is the error:
{"time":"2019-09-24T14:39:46.89404124Z","id":"","remote_ip":"000.00.000.00","host":"pdf-doc-convert.example","method":"POST","uri":"/convert/office","user_agent":"axios/0.19.0","status":500,"error":"getting multipart form: no multipart boundary param in Content-Type","latency":221460,"latency_human":"221.46µs","bytes_in":0,"bytes_out":36}
This is the service documentation, is a simple post with a multipart/form-data request (come with a curl example):
https://thecodingmachine.github.io/gotenberg/#office
And this is my request with axios:
async function request() {
const endpoint =
"http://pdf-doc-convert.example/convert/office";
const data = new FormData();
data.append('files', fs.createReadStream("my/file/path/example.docx"));
const config = {
headers: {
"content-type": "multipart/form-data"
}
};
const pdf = await axios.post(endpoint, data, config);
}
How can i make the request?
Maybe the quickest way to debug this would be to intercept the call you're making with the Axios request using Postman Intercept and to compare the cURL request info from the one that's working to the one that's not. It could be either a headers issue or file encoding issue.
I've encountered something similar previously and this could be related to the formData headers which require additional configuration in Axios as mentioned here: https://github.com/axios/axios/issues/789#issuecomment-508114703
const data = new FormData();
data.append("firstFile", fs.createReadStream(firstFilePath), { knownLength: fs.statSync(firstFilePath).size });
const headers = {
...data.getHeaders(),
"Content-Length": data.getLengthSync()
};
const endpoint = "http://pdf-doc-convert.example/convert/office";
const pdf = await axios.post(endpoint, data, config);

Resources