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

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.

Related

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

Sending pdf files to user from nodejs to reactjs

I have pdf documents stored in the file system on the server side.
I need to let the user download one of them when he/she clicks on download.
The problem is that I know how to send a file from NodeJS to browser but here the request will be made by a ReactJS axios request. So when I send a file, the response will go to react. How do I send that pdf file to the user? Do I access the file system directly using my front end code?
I get the following in the browser console when I log the response after I do res.sendFile(file_path) in NodeJS
How do I process this so that I can make the user download the pdf?
You can use file-saver to download the file. Below is the function I'm using for pdf download. (response.data is the Buffer that nodejs sends back as a response)
import FileSaver from 'file-saver';
...
_onPdfFetched() {
FileSaver.saveAs(
new Blob([response.data], { type: 'application/pdf' }),
`sample.pdf`
);
}
or you can just show pdf to the user
window.open(response.data, '_blank');
Edit
The axios call should be like this:
axios.get(url, {
responseType: 'arraybuffer',
headers: {
Accept: 'application/pdf',
},
});
Edit 2
The nodejs code should be like this:
router.post('/api/downloadfile',(req, res, next) => {
const src = fs.createReadStream('path to sample.pdf');
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=sample.pdf',
'Content-Transfer-Encoding': 'Binary'
});
src.pipe(res);
});

How can I fetch an url using session data from puppeteer page?

I'm trying to enter a website with my credentials and download a pdf using puppeter. I got the pdf url using puppeteer, but now I want to use node-fetch to access that page. To fetch the pdf page I need to include the session data on options, but I don't know if I am doing it the right way.
I tried using 'credentials: 'include', getting the cookies with page.cookies and other small modifications in the options sent with the fetch.
var response = await page.goto(urlPdf);
var headersPup = response.request().headers();
const { cookies } = await page._client.send("Network.getAllCookies", {});
const sessionFreeCookies = cookies.map((cookie) => {
return {
...cookie,
expires: Date.now() / 1000 + 10 * 60,
session: false
};
});
headersPup['Cookie'] = sessionFreeCookies; //adding the cookies to header
headersPup['Content-Type'] = 'application/pdf';//adding content-type
var opts = {
method: "GET",
headers: headersPup,
credentials: "include",
}
await fetch(urlPdf,opts).then(response => response
.body.pipe(fs.createWriteStream('test4.pdf'))
.on('close', () => console.log('pdf downloaded')));
When I open test4 as txt I can see the login page html, it means I lost the session. How can I keep the session to download my pdf?
Of course fetch method can't keep the session, it is not opened in your headless browser.
Unfortunateley seems pdf downloading is not supported on puppeteer: https://github.com/GoogleChrome/puppeteer/issues/1248
In general to be logged in you need to goto(loginPage) adn then goto the page that you need, cookies are managed within the page object.

Downloading Excel data using Axios from Laravel backend is not working

I am developing a Web application using React JS for the front-end and Laravel for the back-end API. Now, what I am trying to do is I am trying to fetch the Excel data from the backend using Axios and then download the file.
This is my Laravel API controller action method.
function downloadExcel(Request $request)
{
//other code goes here
return Excel::create($left_photo->id . "-" . $right_photo->id, function($excel) use ($excel_data)
{
// Set the spreadsheet title, creator, and description
$excel->setTitle('Mapping points');
$excel->setCreator('Laravel')->setCompany('Memento');
$excel->setDescription('Mapping points file');
// Build the spreadsheet, passing in the payments array
$excel->sheet('sheet1', function($sheet) use ($excel_data)
{
$sheet->fromArray($excel_data, null, 'A1', false, false);
});
})->download('xlsx');
}
I fetch the data from the react js application using Axios like this.
export const getHttpClientFileDownload = (path) => {
let accessToken = localStorage.getItem("access_token");
return Axios({
url: getApiBaseEndpoint() + path,
method: 'GET',
responseType: 'blob', // important
headers : { 'api-version': API_VERSION, 'Authorization': 'Bearer ' + accessToken }
})
}
exportExcel()//this is the download medthod in the component
{
let path = 'photos/matching-points/excel?left_photo_id=' + this.props.leftImageId + "&right_photo_id=" + this.props.rightImageId;
//let path = "curator/event/" +this.props.match.params.id + "/details";
getHttpClientFileDownload(path)
.then((response) => {
alert('Everything is alright')
})
}
As you can see in the above code, if the request success, it should alert a message, "Everything is alright". But it is not alerting the message. But in the browser, it is successful.
When I make the request to the link that is returning just normal JSON response, it is alerting the message as expected. Only it is not working as expected when I make the request to the aforementioned Excel API.
I cannot use direct download link because I am doing some authorization on the server-side.
I had the same problem and found a solution as below.
Steps:
Call API to Laravel backend. Create file and store the same in local driver on server.
Return the file name to client.
Create a public route in Laravel (In web.php) to download files from Local storage. This route will delete the file after download it.
From client side, redirect the user to this public URL with the file name.
My code looks like this. I used fetch API.
Client side code:
const response = await fetch("my_server_url.com/api/createFile", {
method: 'GET',
headers: {
Authorization: "Bearer " + this.$store.state.AccessToken,
"X-Requested-With": "XMLHttpRequest",
},
});
if (!response.ok) {
console.log(response)
throw new Error("Something went wrong!");
}
const data = await response.json();
window.open("my_server_url.com/downloadFile/name="+data, '_blank');
Code in my_server_url.com/api/createFile route: (api.php)
public function createFile()
{
$file_name= date('YmdHis').rand();
Excel::store(new myExport(), $file_name.'.xlsx', 'local');
return response()->json($file_name.'.xlsx', 200);
}
Code in my_server_url.com/downloadFile/name={file_name} route: (web.php)
public function downloadFile($file_name)
{
return response()->download(Storage::path($file_name))->deleteFileAfterSend(true);
}
This way, you can check authorization and logic, but yet using the API. Also, make sure to add use Illuminate\Support\Facades\Storage; in laravel controller.
You can simply use window.open(path) to download files

Sending Audio Blob data from a React frontend to a Express backend

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

Resources