I made a simple downloadable response from my express server.
app.post("/download", (req, res) => {
let file_name = req.body.name;
res.download(path.join(__dirname, `files/${file_name}.mp3`), (err) => {
console.log(err);
});
});
And I used axios and js-file-download to download the responsed file from frontend. The file is donwloaded with full file size. But it's not playable.
Axios.post("http://localhost:3001/download", { name: name }).then(
(response) => {
fileDownload(response.data, `${title}.mp3`);
}
);
How can I solve this problem?
In my opinion, every Axios release from v1.0.0 has been fundamentally broken.
The request you're making is trivially easy using the built-in Fetch API and won't be subject to Axios' poor testing and broken releases.
fetch("http://localhost:3001/download", {
method: "POST",
body: JSON.stringify({ name }),
headers: { "content-type": "application/json" },
})
.then((res) => (res.ok ? res.blob() : Promise.reject(res)))
.then((file) => {
fileDownload(file, `${title}.mp3`);
});
Related
Hey guys I have a question regarding the fetch function from JavaScript and the Package Nodemailer.
NOTE: I am using Expo.
I have a PDF created on my Emulator which looks good (filled with data). Now I want to send this PDF to my Backend and therer I want to send the File out as a PDF and get it in my Mails.
Frontend fetch-Call for my Backend:
async sendMonthReportMail(fileUri) {
await fetch(`${connectionString}/api/mails/sendmonthreport`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
senderUser: "My Name",
recieverMail: "myname#mymail.com",
pathMonthLock: `${fileUri}`
})
})
.then(res => res.json())
.then(res => {
console.log("Success SendMailMonthLock - " + res)
})
.catch(err => console.log("Error SendMailMonthLock - " + err))
}
I have also tried to use formData and change the Content-Type to "application/pdf" but this did not work.
Now my Backend Code looks like this:
router.post("/sendmonthreport", async (req, res) => {
const {recieverMail} = req.body;
const {senderUser} = req.body;
const {pathMonthLock} = req.body;
let transport = nodemailer.createTransport({
host: "mailserver",
port: xx,
secure: false,
tls: {
rejectUnauthorized: false
}
});
var message = {
from: "My Sendermail <sender#mail.com>",
to: `${recieverMail}`,
subject: `Mail comming from - ${senderUser}`,
text: `EmailText `,
attachments:[{
filename: "MyFilename.pdf",
content: __dirname + `./${pathMonthLock}`,
}]
}
await transport.sendMail(message)
.catch(err => console.log("Error Mail: " + err ))
res.send("email send")
})
Now the way that I choose the file.uri is threw the DocumentPicker for Expo.
The Problem I am having now is, that the Mail gets send correctly and there is a PDF attached to it with the correct name. However when I look at the PDF Size it is only 500Bytes and it is completly empty. When trying to open the File that is send via Mail then it tells me that the File is corrupted or wrong format.
How can I send the actual content that is inside the PDF?
When I try to use formData:
async sendMonthReportMail(file) {
fdPost.append("file", file);
fdPost.append("senderUser", "User Name");
fdPost.append("recieverMail", "username#mail.com");
console.log(fdPost);
await fetch(`${connectionString}/api/mails/sendmonthreport`, {
method: "POST",
headers: {
accept: "application/json"
// "Content-Type": "multipart/form-data",
// "Content-Type": "application/json",
// "Content-Type" : "application/pdf"
// "Content-Type": "application/x-www-form-urlencoded"
},
body: fdPost
})
.then(res => res.json())
.then(res => {
console.log("Success SendMailMonthLock - " + res)
})
.catch(err => console.log("Error SendMailMonthLock - " + err))
}
fdPost is defined at the top of my file, console.logging it gives me a valid FormData but the request ends with a Network Error!
Error SendMailMonthLock - TypeError: Network request failed
Also my Backend does not react to that call.
I also tried to use RN Fetch Blob but it only works in React Native only Projects. I am using Expo so this is not a soultion for me!
Edit:
I tried the suggestion in the comments (using Multer):
Frontend:
async sendMonthReportMail(file) {
fdPost.append("file", file);
fdPost.append("senderUser", "name");
fdPost.append("recieverMail", "mail#mail.com");
await fetch(`${connectionString}/api/mails/sendmonthreportTest`, {
method: "POST",
headers: {
Accept: "application/json",
'Content-Type': 'multipart/form-data'
},
body: fdPost
})
.catch(err => console.log("Error SendMailMonthLock - " + err))
}
Backend:
router.post("/sendmonthreportTest", upload.single("file"), (req, res) => {
console.dir(req.file + req.body);
})
Still I have the same issue! It gives me TypeError: Network Error.
Also when I try to call that point with Postman I am getting:
POST /api/mails/sendmonthreportTest 500 6.952 ms - 1221
TypeError: Cannot convert object to primitive value
To confirm my POST Body when I console.log the fdPost before the fetch:
{"_parts":[["file",{"size":69496,"name":"Monatsbericht_User_Name_Dezember2022.pdf","type":"success","uri":"file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540yxxx%252Fxxx/DocumentPicker/2xx07e4-4136-4b6f-ad70-26xxac64064.pdf","mimeType":"application/pdf"}],["senderUser","User Name"],["recieverMail","user#mail.com"]]}
I am trying to make some modifications to my Rest API by making the PUT request using request package but it does not seem to work so. Although I am able to make the modifications to the same API using the same JSON body using the Postman. Also, I am not getting any errors so not understanding what's wrong.
Since request was not working, I tried axios even with that no response no error. Following is my sample code which is making request to my Rest API:
const request = require('request');
const axios = require('axios');
const https = require('https');
request(
{
url: testIdUrl,
method: 'PUT',
agentOptions: {
rejectUnauthorized: false
},
headers: [{
'content-type': 'application/json',
body: JSON.stringify(requestBody)
}]
},
function(error, response, body) {
if(error){
console.log("SOMETHING WENT WRONG")
console.log(error)
}
console.log("RESPONSE FROM TEST ID PUT")
})
axios.put(testIdUrl, requestBody)
.then((res) => {
console.log(`Status: ${res.status}`);
console.log('Body: ', res.data);
}).catch((err) => {
console.error(err);
});
Can someone please help me understand what's wrong with the code? Does my Rest API include all the tokens and information? When I use the same requestBody and URL then its works in POSTMAN.
What I want to do is make a curl request which has an authorization token as a header and then I want to save the file in the local directory.
I am trying to use request function trying to achieve that but don't have much success of it.
it('Testing something', () => {
cy.request({
method: 'GET',
url: 'http://google.com/request',
auth: {
bearer: token
},
encoding: 'binary'
}).then((response) => {
//Validate the response
});
});
const options = {
url: `http://google.com/request/download`,
headers: {
'Authorization': `Bearer token`
},
method: 'GET'
};
const result = https.get(options, response => {
if(response.statusCode == 200){
const fileStream = fs.createWriteStream(destinationFolder);
request(response.request).pipe(fileStream);
}
});
});
Problem: When I run above code the file is not downloaded in the destination folder. I just want to download the file and that will make my test complete. I can download the file using curl request. Is there a way that we can mimic curl request in cypress test.
Note: This is a part of cypress test.
Well I figure it out how to acheive it, I am not sure if it is a right approach or not but following is my solution.
I used location in my curl request in order to download the file.
In order to make a curl request from cypress, I used cy.exec :
cy.exec{'curl request', (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
MRE -> node-server : react app
When I send a POST request using Postman, I get the expected result. This is the request that I am sending using Postman
and test sent gets printed to the console of my node server
If I send a request from my react form however, test sent does not print to the console, but the catch block of my fetch request get's executed and err is printed to the console of my react app, followed by {}.
I would like to know why my POST request is not working and is not getting received by the server
Below is the function that I call when someone clicks the submission button of my form created in react
Function called on form submission
nodeUrl = 'https://localhost:6060?'
const submitData = async () => {
fetch(nodeUrl, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({'test': 'test'})
}).then((res) => {
alert('then')
}).catch((err) => {
alert('err')
alert(JSON.stringify(err))
})
}
}
This is the server that I run using node server.js
server.js
server.post('/', function(req, res) {
console.log('test sent')
mailer.messages().send(req.body)
.then((mes) => {
console.log(mes)
res.json({ message: 'Thanks for your message. Our service team has been notified and will get back to you shortly.' })
}).catch(err => {
console.log(err)
res.json(err);
})
});
The majour issue here is due to CORS. CORS support can be used to overcome this. Just keep in mind to have this only for development mode(see below codes).
But, as per the Postman's snapshot and provided GitHub repositories, the request from Front-end should be of multipart/form-data type. Thus, the Front-end code would look like this
const nodeUrl = "http://localhost:6060/";
const submitData = async () => {
// create a FormData object
const formData = new FormData();
formData.append('form', 'example#email.com');
formData.append('to', 'example#email.com');
// this auto adds 'multipart/form-data' + HASH header in the request
fetch(nodeUrl, {
method: "POST",
body: formData
})
.then(res => {
console.log(res);
}).catch(err => {
console.log('Error -', err);
});
};
To handle multipart/form-data request in the ExpressJS, you need a plugin Multer.
const express = require('express');
const bodyParser = require('body-parser');
const multer = require('multer'); // for 'multipart' type request
const server = express();
const upload = multer();
// allow CORS requests in development mode
if (process.env.NODE_ENV === 'development') {
// Server run command - "NODE_ENV=development node server.js"
const cors = require('cors');
server.use(cors());
}
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({extended: true}));
// using Multer middleware form extracting 'FormData' payload
server.post('/', upload.none(), function(req, res) {
console.log('Received body', req.body);
... // other codes
});
Strategy 2(plain JSON) -
If that 'multipart/form-data' strategy was unintentional and you just want to send simple JSON, use below codes -
In Front-end, trigger API request as -
fetch(nodeUrl, {
method: "POST",
headers: {
'Content-Type': 'application/json', // this needs to be defined
},
body: JSON.stringify({ from: 'some#email.com', to: 'other#email.com' })
})
In server, just ignore codes related to Multer and only keep your API as -
server.post('/', function(req, res) {
console.log('Received body', req.body);
... // other codes
});
I ended up using a better fetch request, which was put together for me by selecting code -> Javascript Fetch in Postman(under the save button)
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("from", "example#email.com");
urlencoded.append("test", "test");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http:localhost:6060/, requestOptions)
.then(response => {
if (response.ok){
response.json().then(json => {
console.log(json)
})
}
})
.catch(error => console.log('error: ', error))
I'm trying to create a login form using sapper, but am encountering the following problem when trying to test a basic POST fetch.
In routes/login/login.svelte, I have the following code which is called on a button click:
<script>
let data = {"email":"test"};
const handleLogin = async () => {
const response = await fetch("/login/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: data
});
};
</script>
Which should send what is in data to routes/login/login.js which has the following code:
export async function post(req, res, next) {
res.setHeader('Content-Type', 'application/json');
var data = req.body;
return res.end(JSON.stringify(data));
}
My problem is that this only returns {} rather than the data sent in the svelte page. Any ideas as to why this is happening and where I'm going wrong? Thanks.
When sending the data, you should also stringify it there
body: JSON.stringify(data)
as an extra make sure you have body-parser installed and added as middleware in the server, this package will help you handle requests that have send json data in their body.
polka() // You can also use Express
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
bodyparser(),
sapper.middleware()
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Building on the previous answer, I'm writing here the full working solution. Your problems may be due to:
Not using the json parse middleware
Not treating fetch as a promise
Here's how I'd fix it:
npm i body-parser
Add the json middleware in your server.js
const { json } = require('body-parser');
polka()
.use(
compression({ threshold: 0 }),
json(),
sirv('static', { dev }),
sapper.middleware()
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Treat the fetch response as a Promise. This is how your Svelte component should look like (notice the chained then):
<script>
let data = {"email":"test"};
const handleLogin = async () => {
await fetch(`your-endpoint`, {
method: 'POST',
body: JSON.stringify(data),
headers:{
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(res => console.log(res)); // {email: "test"}
};
</script>