How to send json data to client side from express nodejs - javascript

I have an application, where I need to send the form data through XMLHttpRequest. When I send that information over, I then need to validate the form, then send information back to the client based on if the form validates or not. I'm using nodejs with express.
My client side code is:
editor.save().then((output) => {
let formData = new FormData();
const xhr = new XMLHttpRequest();
formData.append('name', document.getElementById('inputProductName').value);
xhr.open('post', '/items/add', true);
xhr.send(formData);
}).catch((error) => {
console.error('Error: ' + error);
return;
}).finally(() => {
// This is where I need to retrieve the validation code and redirect accordingly.
if (success == false) {
window.location.href = '/items/add/failed';
} else {
window.location.href = '/items/add/success';
}
});
My server side code is this:
router.post('/add', (req, res) => {
let form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (fields.name.length < 1) { // If the name is empty
res.status(200).json({
success: false,
message: 'Product name must be specified'
});
} else {
res.status(200).json({
success: true,
message: 'Product added successfully'
});
}
});
});
So if the the validation fails, then I want to be able to get the success and message variable through the client end if possible.

Have a look at using fetch API from MDN docs
fetch data via POST
await response
based on response.success act accordingly
Additionally,looking a the server-side code, it doesn't appear necessary that form encoding be used.
Suggest sending the data in json format and have the server check the request.body for the appropriate field to be populated.
pseudo code
editor.save().then(async (output) => {
let formData = new FormData();
formData.append('name', document.getElementById('inputProductName').value);
const response = await fetch(url, {
method: 'POST',
// ... additional form data here, looks like you can send JSON, no need for form encoding
}
if(response.success) {
window.location.href = '/items/add/success';
} else {
window.location.href = '/items/add/failed';
}
}).catch((error) => {
console.error('Error: ' + error);
return;
})
Note that the anonymous function () => {} is now async () => {} to allow await on the fetch call.
async / await

Related

How to get the details on backend nodejs with the GET request in angular

I am unable to fetch the query parameters of frontend GET request, on the backend side.
I tried using url and query. I need to fetch the query on the nodejs side.
Kindly suggest a suitable method that would help me get the details on GET request using axios.
code -
component.ts - angular file
googleSearch(googleText){
let params = new HttpParams();
params = params.append('q', googleText.trueLocation);
return new Promise((resolve, reject) => {
this.httpClient.get("http://localhost:3003/seekSearchApi" , ({params:params}))
.pipe(map(Response => Response))
.pipe(catchError(this.errorHandler))
.subscribe((res: Response) => {
this.writeItOutput = res;
resolve(this.writeItOutput);
});
})
}
errorHandler(error: HttpErrorResponse) {
return throwError(error.message || 'server Error');
}
}
server.js- express file
app.use('/seekSearchApi', require('./server/nodejs-serverapi'));
applicationserver.js - nodejs file
function seekSearchApi(req,res) {
var query = require('url').parse(req.url,true).query;
console.log("req.query.q", query.q); //no response
console.log("Inside seekSearchApi");
axios({
method: 'get',
url: 'https://serpapi.com/search.json?',
data: {
api_key: "xxxx",
q:query.q
hl: "en",
gl: "us",
google_domain: "google.com"
}
}).then((response) => {
res.send(stringify(response))
}, (error) => {
console.log(error);
});
I figured it out .
On node side.
applicationserver.js
function seekSearchApi(req,res) {
var url_data = url.parse(req.url, true);
var query = url_data.query;
var queryData= Object.assign({},query);
console.log("queryData = ", queryData);
::::
}

PUT form-data axios vue.js

I just updated my User model with "avatar" field so I can upload a photo. I used a PUT method already configured and just added avatar to it. In postman the file upload (form-data) it works just fine, but when trying to upload it using axios from vue.js it doesn't work. I tried in many ways, the last one, I tried to send the request as multi form data.
async saveChanges() {
const fd = new FormData();
fd.append("id", this.$auth.user().id);
fd.append("username", this.$auth.user().username);
fd.append("email", this.user.email);
fd.append("firstName", this.$auth.user().firstName);
fd.append("lastName", this.$auth.user().lastName);
fd.append("isAdmin", this.$auth.user().isAdmin);
fd.append("password", this.user.password);
fd.append("confirmpass", this.user.confirmpass);
fd.append("avatar", this.selectedFile, this.selectedFile.name);
fd.append("_method", "put");
try {
await this.axios.put(`/users/${this.$auth.user().id}`, {
fd
}).then((res) => {
console.log(res);
});
} catch (err) {
console.error(err);
}
}
After i choose the file, it is available, but I am unable to send it trough my method. Should i create another request just for updating the avatar or is it possible to solve this?
Try this
axios.put('/users/${this.$auth.user().id', fd, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Pass your method as post method and define put in form data
formData.append('_method', 'PUT') .
async handleSubmit() {
let formData = new FormData();
formData.append('image', this.file);
formData.append('title', this.form.title);
formData.append('_method', 'PUT')
try {
const response = await axios.post(`image-update/${this.$route.params.id}`, formData)
this.$router.push('/');
console.log(response);
} catch (e) {
this.error = 'Something error found !';
}
}
My previous wrong code that return empty result in $request->all()
let data = new FormData()
data.append('message', 'AnyMessage')
Then I change it as follows and it's working fine -
let data = "message=AnyMessage"

How to send a file in array of object to express server?

I have an array of the object, each object contains some properties of type string and a file.
This is how my array looks like:
const args = [
{
name: 'presentation',
price: 9.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
},
{
name: 'presentation2',
price: 20.99,
tags: 'invest, finance, business',
file: File,
thumbnail: File
}
]
const headers = {
headers: {
Authorization: `Bearer ${token}`
}
};
My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3.
But Currently, I am unable to get the file stream on the server when I send this in a POST request,
even the whole req.body is an empty object when I console.log it
axios.post(`${slidesRoute}/createSlides`, args, headers);
Alternatively, I tried to put everything into FormData.
for example:
let formData = new FormData();
selectedFiles.forEach((selectedFile, i) => {
formData.append(`name_${i}`, selectedFile.name);
formData.append(`price_${i}`, selectedFile.price);
formData.append(`tags_${i}`, selectedFile.tags);
formData.append(`file_${i}`, selectedFile.file);
formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
});
axios.post(`${slidesRoute}/createSlides`, formData, headers);
Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like
file_1, file_2 file_3,...
But multer expects the exact filename to be passed
for example multer().array('file')
so in my second approach I am unable to catch files using Multer
You can't include file inside JSON. File is not JSON-serializable. Ideally you should have a separate endpoint to accept your files, send them with content-type: multipart/form-data, receive unique id for that file stored on the server, then send your JSON with ids instead of files.
As a chaper alternative you can Base64 encode your files into a string, insert this string in your request, and then decode it back on the receiving side
FormData key values are array by default
in your code Just change
formData.append(`file_${i}`, selectedFile.file);
to
formData.append(`file`, selectedFile.file);
You should be able to receive the file array in server side using multer().array('file')
Sample below demonstrating FormData key values array behavior
const formData = new FormData();
formData.append('key1', 'value1');
formData.append('key1', 'value2');
formData.append('key2', 'value1');
formData.forEach(function(value, key){
console.log(key, value);
});
I use FormData to send a number of files - and then on the node.js server I use Formidable.
I've pasted some partial code below that may help - sorry it's not a smaller sample.
Hope it helps
On the browser side I have:
let form_data = new FormData()
form_data.append('upload_data', file)
$.ajax({
url: '/file/upload' + remote_path + '/' + filename,
type: 'POST',
data: form_data,
processData: false,
contentType: false,
success: (res) => {
...
On the node.js side (apologies for the length..)I have:
const fs = require('fs')
const formidable = require('formidable')
const path = require('path')
...
app.post('/file/upload/*', (req, res) => {
let filename = req.params[0]
let media = path.basename(filename)
let folder = filename.substring(0, filename.length - media.length)
let form = new formidable.IncomingForm()
// form.encoding = 'utf-8'
form.multiples = true
form.uploadDir = path.join(media_folder, folder)
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
if (err) {
fail(res, 'failed to upload')
} else {
success(res)
}
})
form.on('fileBegin', (name, file) => {
const [fileName, fileExt] = file.name.split('.')
file.path = path.join(form.uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
})
form.on('file', (field, file) => {
fs.rename(file.path, path.join(form.uploadDir, file.name), (err) => {
if (!res.headersSent) { // Fix since first response is received
fail(res, 'an error has occured with form upload' + err)
}
})
})
form.on('error', (err) => {
fail(res, 'an error has occured with form upload' + err)
})
form.on('aborted', (err) => {
fail(res, 'Upload cancelled by browser')
})
})

Axios 419 (unknown status) Laravel API csrf token gets changed

I'm getting the error when I'm requesting my Laravel backend with Axios and getting the data back and requesting another API for some data and that goes well but after the API returns the data and I request my laravel backend to store the data. It returns a response with
app.js:360 POST http://technotrace.tech/session-adding-api 419 (unknown status)
I've tried checking on my PHP backend and this only stops if I'm disabling the VerifyCSRFToken middleware group.
But I need to check the CSRF token anyway for security reasons.
I'm able to understand why the csrf token gets changed on sending request.
If I'm doing just sending the request to my laravel backend then everything goes right but when I'm requesting another api then the problem arrives on sending the request to my backend.
function addSession(url, formdata) {
//Add Session
axios.post(url, formdata)
.then(res => {
console.log(res)
var data = res.data;
if ((data.session_info != null && data.session_info != {})) {
console.log(data.session_info);
}
})
.catch(err => {
console.error(err);
})
}
function getApiDetails() {
//Start getting api details
axios.get('https://ipapi.co/json/').then(res => {
console.log(res)
var csrf = jr('meta[name="csrf-token"]').get(0).content;
var ses_id = jr('meta[name="verify-token"]').get(0).content;
var cur_url = jr('link[rel="canonical"]').get(0).href;
// console.log(csrf, ses_id, cur_url);
var url = '/session-adding-api';
var formdata = new FormData();
formdata.append('_token', csrf);
formdata.append('session_token', ses_id);
formdata.append('session_repeat', 0);
formdata.append('current_url', cur_url);
Object.entries(res.data).forEach(entry => {
// console.log(entry[0], entry[1]);
formdata.append(entry[0], entry[1]);
});
addSession(url, formdata);
})
.catch(err => {
console.error(err);
})
//End getting api details
}
function matchSession() {
//Match Session Start
var csrf = jr('meta[name="csrf-token"]').get(0).content;
var ses_id = jr('input[name="verify-token"]').get(0).content;
var url = '/session-matching-api';
var formdata = new FormData();
formdata.append('_token', csrf);
formdata.append('session_token', ses_id);
axios.post(url, formdata)
.then(res => {
console.log(res)
var data = res.data;
if ((data.match != true)) {
getApiDetails()
}
})
.catch(err => {
console.error(err);
})
//Match Session
}
matchSession();

Retrieve data from external static JSON file and use in AWS Lambda

I am looking to pull some data from an external static JSON file based on an event sent to AWS Lambda.
So when someone sends their "customer_id" we pull the matching "email" and "option" from the external JSON file
https://3objects.netlify.com/3objects.json
Here is the code I have so far?
const AWS = require('aws-sdk');
const ses = new AWS.SES();
const request = require('request');
exports.handler = (event) => {
console.log(event.customer_id);
request({
url: 'https://3objects.netlify.com/3objects.json',
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
})
}, function (error, response) {
if (!error && response.statusCode == 200) {
var jsonResponse = JSON.parse(body); // turn response into JSON
// do stuff with the response and pass it back to Lambda...
});
// After JSON data retrieval of 'email' and 'option' from https://3objects.netlify.com/3objects.json we send them an email with this info
clientEmail = email;
contact_option = option;
var eParams = {Destination: {ToAddresses: [clientEmail]}, Message: {Body: { Text: { Data: 'Your contact option is ${contact_option}' },},Subject: { Data: "Your Contact Preference" }}, Source: "sales#example.com"};
var email = ses.sendEmail(eParams, function (err, data) { if (err) console.log(err); else { console.log("===EMAIL SENT==="); } });
};
How can I query and use that external JSON url data?
I prefer to using node-fetch. It is a package that let you use the fetch function from ES6.
I created an example of using node-fetch. The function getCustomers gets the customers from the url.
Then I created a function that returns a Promise. Inside this Promise, the retrieved data is send by mail using AWS.SES().
const AWS = require('aws-sdk'),
ses = new AWS.SES(),
fetch = require('node-fetch');
exports.handler = async (event) => {
console.log(event.customer_id);
const customers = await getCustomers();
customers.map(async customer => {
await sendEmailToCustomer(customer);
});
}
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
console.log(json);
return json;
}
catch(e) {
throw e;
}
}
const sendEmailToCustomer = (customer) => new Promise((resolve, reject) => {
ses.sendEmail({
Destination:
{ ToAddresses: [customer.email] },
Message:
{
Body: { Text: { Data: `Your contact option is ${customer.customer_id}` }},
Subject: { Data: "Your Contact Preference" }
},
Source: "sales#example.com"}, (error, result => {
if (error) return reject(error);
resolve(result);
console.log(result);
})
}
In general, you should post the exact error you're facing instead of general question. it would help contributors to figure out the problem you're facing.
In your code snippet above, the part
// After JSON data retrieval of 'email' and 'option' from https://3objects.netlify.com/3objects.json we send them an email with this info
clientEmail = email;
contact_option = option;
var eParams = {Destination: {ToAddresses: [clientEmail]}, Message: {Body: { Text: { Data: 'Your contact option is ${contact_option}' },},Subject: { Data: "Your Contact Preference" }}, Source: "sales#example.com"};
var email = ses.sendEmail(eParams, function (err, data) { if (err) console.log(err); else { console.log("===EMAIL SENT==="); } });
is executed before the request returns. You need to move that code inside your callback to execute it when the request finishes.
I also would suggest you to convert your code to async/await for better readability and avoid this type of error.
See this article to learn how to do that : https://www.stormacq.com/2019/06/22/async-js.html

Categories