FormData() append - Receive only empty objects - javascript

I started a new project and had never issues to append data to FormData and sending it to the backend. Currently, I receive only empty objects in the backend. What am I missing here?
this.first_name is not empty if I console.log it. That's not the problem here.
async createAgent() {
const data = new FormData()
data.append('first_name', this.first_name)
// data.append('last_name', this.last_name)
// data.append('phone', this.phone)
// data.append('email', this.email)
// data.append('languages', this.checkedLanguage)
// data.append('image', this.selectedFile)
try {
const post = await this.$axios.$post('/api/create-agent', data)
}
Node.js
exports.createAgent = async (req, res) => {
console.log(req.body.first_name);
console.log(req.body);
};
Console Output
undefined
{}
index.js (Node.js)
const app = express();
app.use(morgan("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

According to body-parser's docs:
This does not handle multipart bodies, due to their complex and typically large nature.
which in your screenshot, on the Request Headers part, is stated.
Solutions in your example are:
just send a JSON payload (parsed by bodyParser.json())
set Content-Type to application/x-www-form-urlencoded (parsed by bodyParser.urlencoded())
use the recommended modules for multipart body in the docs:
Docs: https://github.com/expressjs/body-parser/tree/1.20.0#readme
To send a JSON payload with axios which you are using in the OP, do:
axios.post({
first_name: "This is a JSON property"
})
or
$axios.$post()
which IF you're using nuxt/axios, is a convenient function that will return the response body instead of the whole response.
Docs: https://axios.nuxtjs.org/usage#-shortcuts

Related

Parse sendBeacon data in Express

I'm trying to start logging my own WebVitals. The simple use-case in their example docs looks like this:
function sendToAnalytics(metric) {
// Replace with whatever serialization method you prefer.
// Note: JSON.stringify will likely include more data than you need.
const body = JSON.stringify(metric);
// Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
(navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
fetch('/analytics', {body, method: 'POST', keepalive: true});
}
That all seems simple enough. Here's my actual implementation:
function sendToLog(metric) {
// Replace with whatever serialization method you prefer.
// Note: JSON.stringify will likely include more data than you need.
const body = JSON.stringify(metric);
console.log(`Sending body ${body}`);
// Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
// (navigator.sendBeacon && navigator.sendBeacon('https://localho st:9292/api/log', body)) ||
fetch('https://localhost:9292/api/log', {body: body, method: 'POST', headers: { 'Content-Type': 'application/json' }, keepalive: true});
}
I had to modify the fetch to include the "body" property name and add headers to get it to work, but that is now working. However, if I uncomment the navigator.sendBeacon line, I just get {} for the body.
I'm using NodeJS and Express on the backend. My starting point was this:
const app = express();
app.use(
express.json({
// We need the raw body to verify webhook signatures.
// Let's compute it only when hitting the Stripe webhook endpoint.
verify: function (req, res, buf) {
if (req.originalUrl.startsWith(API_PREFIX + '/webhook')) {
req.rawBody = buf.toString();
}
},
})
);
app.use(cors());
// Expose an endpoint for client logging.
app.post(API_PREFIX + '/log', async (req, res) => {
const message = req.body;
console.log('Got message');
console.dir(message, { depth: null });
logger.info(message);
res.sendStatus(200);
});
There's this similar question, where the accepted answer suggests that adding body-parser and app.use(bodyParser.raw()) should do the trick, and then in the comments there's discussion of using bodyParser.json()) instead.
I've tried both of those:
import bodyParser from 'body-parser';
...
//app.use(bodyParser.raw());
//app.use(bodyParser.json());
app.use(
express.json({
// We need the raw body to verify webhook signatures.
// Let's compute it only when hitting the Stripe webhook endpoint.
verify: function (req, res, buf) {
if (req.originalUrl.startsWith(API_PREFIX + '/webhook')) {
req.rawBody = buf.toString();
}
},
})
);
app.use(cors());
(i.e., uncommenting either of the two lines at the beginning), and in all 3 cases I still get an empty body when sendBeacon is used.
The Express documentation says,
[express.json] is a built-in middleware function in Express. It
parses incoming requests with JSON payloads and is based on
body-parser....A new body object containing the parsed data is
populated on the request object after the middleware (i.e. req.body),
or an empty object ({}) if there was no body to parse, the
Content-Type was not matched, or an error occurred.
So, a) I guess I shouldn't need the body-parser, since express.json is just doing that anyhow; and b) I'm hitting one of those three conditions (there's no body to parse, the Content-Type was not matched, or an error occurred). Assuming that's the case, how do I diagnose which one it is, and then fix it (in such a way that the fetch fallback continues to work). Or, if there's some other problem, back to the original question, how do I get this to work? :)
navigator.sendBeacon sends Content-Type: text/plain whereas express.json() only parses the body if Content-Type: application/json.
Use express.text() in combination with JSON.parse(req.body) instead, or additionally:
app.post(API_PREFIX + '/log',
express.json(), express.text(), function(req, res) {
if (typeof req.body === "string") req.body = JSON.parse(req.body);
...
});

Get data from HTTP GET request

I'm sending an HTTP GET request from the client to my server. On the server, I can't access the data that is passed with the GET request. It works for POST requests but the value is not received in the get request.
The client is Vue.js, and the Server is Express.js in Node.js. The code looks like this.
Client:
var response = await axios.get('/endpoint',{ key: 'value' });
Server:
router.get('/endpoint', async (req,res) => {
console.log(req.body); // empty
console.log(req.query); // empty
console.log(req.params); // empty
});
I've set up my body-parser above. It looks like below
const bodyparser = require('body-parser');
app.use( bodyparser.json() );
How do I access the {key: 'value'} object that is sent from the client in my server.
GET requests do not have bodies
With Axios you can path query params to GET call in 2 different ways:
By putting them into the endpoint path
await axios.get('/endpoint?key=value&key2=value2');
Add them to the config argument in params property object as key-value
await axios.get('/endpoint', { params: {key: 'value', key2: 'value2' }});
Your confusion absolutely makes sense, you try to use same way to pass param for get and post methods, but in Axios these methods have different number of arguments: post(url, data, config), get(url, config)
Let's return to your example:
var response = await axios.get('/endpoint',{ key: 'value' });
So now you can see that { key: 'value' } object that you pass as a second argument is request config and isn't a data.
You can learn more about request config params here - https://github.com/axios/axios#request-config
I believe the problem is that you want to access body by
console.log('req.body');
instead of
console.log(req.body);
Also, as pointed above, GET doesn't have body.

Can't parse malformed JSON from Twilio API

I've spent 4 hours trying to parse a simple JSON from Twilio.
The flow is:
Text message containing magnet link
Twilio proxies request to my serverless function on cloud
Parse req. to get the value
Twilio Studio UI
Code
....
var app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
module.exports.magnet = async (event) => {
let requestBody = ''
try {
requestBody = JSON.parse(event.body)
requestBody = requestBody["magnet"]
} catch (err) {
console.error(err)
}
await beginAuth(requestBody
....
I'm just getting malformed JSON. When I play around with stringify and parse together, I just either get malformed error or I get an added \r escape character, which also causes issues.
Not sure if this is just Twilio or me. I just want the magnet link as a string.
I tried
JSON.parse(JSON.stringify(event.body))
but that also didn't help.
Sample Payload
{"magnet": "magnet:?xt=urn:btih:9970E5BF56EDDB06024EF1311109865B893C8EB4&dn=Westworld+-+Season+3+-+Mp4+x264+AC3+1080p&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Feddie4.nl%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969&tr=udp%3A%2F%2Feddie4.nl%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A80&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce"}
Twilio sends the body usually formatted as a query string, i.e. you have to decode it like this:
const querystring = require('querystring');
requestBody = querystring.parse(event.body);
requestBody = requestBody['magnet']
To verify that it's sent as a query string simply print the event.body after receiving it, in your example it should look similar to this:
magnet=magnet%3A%3Fxt%3Durn%3Abtih%3A9970E5BF56EDDB06024EF1311109865B893C8EB4%26dn%3DWestworld%2B-%2BSeason%2B3%2B-%2BMp4%2Bx264%2BAC3%2B1080p%26tr%3Dudp%253A%252F%252Ftracker.leechers-paradise.org%253A6969%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.coppersurfer.tk%253A6969%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.coppersurfer.tk%253A80%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.opentrackr.org%253A1337%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.zer0day.to%253A1337%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.pirateparty.gr%253A6969%252Fannounce%26tr%3Dudp%253A%252F%252Feddie4.nl%253A6969%252Fannounce%26tr%3Dudp%253A%252F%252Fcoppersurfer.tk%253A6969%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.leechers-paradise.org%253A6969%26tr%3Dudp%253A%252F%252Ftracker.coppersurfer.tk%253A6969%26tr%3Dudp%253A%252F%252Ftracker.opentrackr.org%253A1337%26tr%3Dudp%253A%252F%252Ftracker.pirateparty.gr%253A6969%26tr%3Dudp%253A%252F%252Feddie4.nl%253A6969%26tr%3Dudp%253A%252F%252Ftracker.coppersurfer.tk%253A80%26tr%3Dudp%253A%252F%252Ftracker.zer0day.to%253A1337%252Fannounce%26tr%3Dudp%253A%252F%252Ftracker.leechers-paradise.org%253A6969%252Fannounce%26tr%3Dudp%253A%252F%252Fcoppersurfer.tk%253A6969%252Fannounce

How is req.body correctly mapped to the const array of variables in here?

I was following along a course and can't understand how does the express correctly maps the values in the JSON of the request's body to the array of const variables.
The raw JSON in the body of the post request is:
{
"status":"Systems Engineer",
"skills":"HTML ,CSS, Python, Machine Learning"
}
In server.js I have initialized Middleware as:
app.use(express.json({ extended: false }));
At backend in profile.js file:
const {
company,
website,
location,
bio,
status,
githubusername,
skills,
youtube,
twitter,
facebook,
linkedin,
instagram
} = req.body;
console.log(status);
console.log(skills);
Output:
"Systems Engineer"
"HTML ,CSS, Python, Machine Learning"
This line of Express middleware:
app.use(express.json({ extended: false }));
reads the body of the request from the incoming http request stream and then parses the JSON found in that request body. The resulting properties from the parsed JSON are put into the object req.body for a subsequent request handler to use the data from there. That middleware populates whatever properties it finds in the parsed JSON.
This part of your code:
const {
company,
status,
skills,
...
instagram
} = req.body;
is called object destructuring in Javascript (nothing to do with Express). It is basically equivalent to this code:
const company = req.body.company;
const status = req.body.status;
const skills = req.body.skills;
...
const instagram = req.body.instagram;
Any property with a named variable that doesn't exist in req.body will just end up with a corresponding variable with an undefined value in it. The ones that do exist will copy the value of that property over to the named variable.
Also, there is no array in your code. The first code block above is object destructuring syntax in Javascript.

Headers not set node.js api push notification

Hello im trying to set up push notifications for my webapp.
I'm getting my subscription like I should.
It saves it to my database correctly.
It sends my notification like it should if there only is ONE user in the db
and i want to send to more than only one user :)
Im using:
Vue.js (framework)
Axios (post)
node.js (api)
mongoDB (database)
Here's my post to API.
await axios({
method: 'post',
url: 'API',
data: {
subscription: JSON.stringify(subscription),
storeId: storeId
},
headers: {
'Content-Type': 'application/json'
}
})
It registreres my post, but then i get an throw error.
that "Can't set headers after they are sent."
I'm using CORS in my app like this:
const cors = require('cors')
const app = express();
app.use(bodyParser.json());
app.use(cors())
app.use(morgan('combined'))
The way I'm handling the post from my website is by finding my subscriptions and then map through and say foreach subscription
webpush
//subscribe routes
app.post('/pushNotification', (req, res) => {
var storeId = req.body.storeId
res.setHeader('Content-Type', 'application/json');
console.log(storeId)
if (req.body.storeId != null) {
console.log('Test1')
//get pushSubscription object
//create payload
const payload = JSON.stringify({ title: 'push test' })
Push.find({
"storeId": storeId
},
'subscription', function(error, response) {
console.log('Test2')
console.log(response)
response.map(item => {
res.status(201).json({});
console.log('Test3')
var subscription = item.subscription
console.log(subscription)
webpush.sendNotification(subscription, payload).catch(err => console.error(err));
})
})
} else {
res.send("failed")
}
})
As i can read around somewhere is it im not setting headers or something right. I have used cors like in tutorials and stuff.
So it's like it is crashing because it iterates wrong.
but i can't see how.
ERROR MESSAGE:
Thanks in advance
you are getting this error because res.status(201).json({}) has already set the headers and sent back the response to the client but webpush.sendNotification also trying to set the headers.You should use only webpush.sendNotification(subscription, payload).catch(err => console.error(err));
res.json([body]) sets the corresponding header and sends the result:
Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().
So, first of all you don't need to set header manually.
second, If the response has more than one item, since you can't send multiple result for a request, you shouldn't use res.json in a map.
Moreover, be aware of webpush.sendNotification that it may send a result too.

Categories

Resources