Sending JSON response from NodeJS/Express - javascript

sorry for the n00b question I have been kinda stuck so I was hoping you guys could put me in the right direction.
I am making an app that is retrieving data by NODEJS from a REST API. (This is a success and works).
I then have a listen URL (my own API) in express that I invoke by going to the browser http://localhost/api or by using POSTMAN. So far so good, I see in the console (NODE Console) that my request gets handled perfectly as I see the JSON response, however, I would also like to see the JSON response in the browser or POSTMAN as JSON Response, not just the console I know I am missing something in my (simple) code but I am just starting out.... Please help me out here is my code.
var express = require("express");
var app = express();
const request = require('request');
const options = {
url: 'https://jsonplaceholder.typicode.com/posts',
method: 'GET',
headers: {
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
}
};
app.get("/api", function(req, res) {
request(options, function(err, res, body) {
var json = JSON.parse(body);
console.log(json);
});
res.send(request.json)
});
app.listen(3000, function() {
console.log("My API is running...");
});
module.exports = app;
Much appreciated!

To send json response from express server to the frontend use res.json(request.json) instead of res.send(request.json).
app.get("/api", function(req, res) {
request(options, function(err, res, body) {
var json = JSON.parse(body);
console.log(json); // Logging the output within the request function
}); //closing the request function
res.send(request.json) //then returning the response.. The request.json is empty over here
});
Try doing this
app.get("/api", function(req, res) {
request(options, function(err, response, body) {
var json = JSON.parse(body);
console.log(json); // Logging the output within the request function
res.json(request.json) //then returning the response.. The request.json is empty over here
}); //closing the request function
});

Much thanks to ProgXx, turned out I used the same res and response names. Here is the final code. Much thanks ProgXx
var express = require("express");
var app = express();
const request = require('request');
const options = {
url: 'https://jsonplaceholder.typicode.com/posts',
method: 'GET',
headers: {
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': 'my-reddit-client'
}
};
app.get("/api", function(req, res) {
request(options, function(err, output, body) {
var json = JSON.parse(body);
console.log(json); // Logging the output within the request function
res.json(json) //then returning the response.. The request.json is empty over here
}); //closing the request function
});
app.listen(3000, function() {
console.log("My API is running...");
});
module.exports = app;

Related

http request not working in nodejs, causing error

I am using expressJS on the back end to make a very simple API since I am a beginner. I am sending a request to the back end from the front end and I expect the front end to receive a response. This works fine until I change the nodejs for it to make a second request before sending the original response back to the client. The process looks something like:
Front end sends a POST request
back end receives request, then:
makes its own POST request to a source
waits for this data to come back, then:
sends back a response to the original request from the front end including the data gotten from the second request.
This process works fine when I remove the few lines of code which send the second request, but when the NodeJs back end makes this second request, I get a 404 error returned to the front end - and this error does not come from the second request.
Here is the code:
front end:
function post() {
return new Promise(() => {
$.ajax("URL of my nodejs backend", {
method: "POST",
cache: false,
data: {
action: "test-https"
},
}).then(response => {
console.log(response);
});
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
nodejs backend (only the bits needed for this question)
const express = require("express");
//const $ = require("./djax.js");
const https = require('https');
const app = express();
app.post("/", (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
const body = [];
req.on("data", (chunk) => {
body.push(chunk);
});
req.on("end", () => {
const parsedBody = Buffer.concat(body).toString();
//res.status(200).send("bod" + parsedBody);
// Now parsedBody will be like a query string: key1=val1&key2=val2
const queryObject = new URLSearchParams(parsedBody);
parseRequest(queryObject, res);
//console.log(parsedBody);
});
//console.log(body);
next();
});
function parseRequest(queryParameters, response) {
// Here, queryParameters is a QueryParams object holding the body of the request
// sendResponseFunc is the function which sends back the response for this
// current request.
// Now, we have access to the body of the request and we can use this
// to call the neccessary functions and logic, after which
// send a response back to the front-end via the second
// parameter
const action = queryParameters.get("action");
switch(action.toLowerCase()) {
// ... other cases ...
case "test-https":
sendHttpsRequest(response);
break;
default:
response.status(200).send("Error: unknown action:'" + action.toLowerCase() + "'");
break;
}
}
function sendHttpsRequest(response) {
const postData = JSON.stringify({
works: true
});
const postOpts = {
host: "httpbin.org", // This is a test-server. Not mine.
path: "/post",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(postData)
}
};
const newReq = https.request(postOpts, result => {
result.setEncoding("utf8");
res.on("data", chunk => {
console.log("Response" + chunk);
response.status(200).send("Request made from NodeJS end came back " + chunk);
});
});
newReq.write(postData);
newReq.end();
}
When I change the sendHttpsRequest function so that it does NOT make a request, like so:
function sendHttpsRequest(response) {
response.status(200).send("Hi");
}
... then the front-end receives the response and there is no error. There is a 500 internal server error only when the second request is made - when the function sendHttpsRequest is like in the penultimate snippet. I have tried to fix this for two days but I have no idea why this error is happening.
How can I make this second request from the NodeJS server and send back the contents of that without causing the 500 error?
You need to have error handling. You cannot expect that external requests will succeed all the time, for that reason you have to have res.on("error", ...) to respond the client appropriately.
However, I don't see a special case why you are using a data listener to collect payload chunks, it can be simplified very much.
Here is a very simple working example for you
// Backend
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const app = express();
const port = 3000;
app.use(express.json()); // Accepts JSON as a payload
app.use(cors());
app.post('/', (req, res) => {
axios
.get('EXTERNAL URL')
.then((response) => {
console.log('Received payload', req.body);
// Handle response
res.json({data: response.data}).status(201);
})
.catch((error) => {
// Handle error
res.json({
message: error.message,
code: 422})
.status(422);
});
});
app.listen(port, '0.0.0.0', () => console.log(`Started at //127.0.0.1:${port}`));
Required dependencies are
ExpressJS cors package
Axios HTTP client
Axios can be used in browsers as well
Here is your jQuery Ajax request which sends JSON payload instead of FormData
// FE jQuery
function post() {
return new Promise((resolve, reject) => {
$.ajax('http://127.0.0.1:3000', {
contentType: 'application/json; charset=utf-8',
dataType: 'json',
method: 'POST',
data: JSON.stringify({
action: 'test-https',
}),
success: (data) => resolve(data),
error: (err) => reject(err),
});
});
}
post().then(console.log).catch(console.error);

Javascript fetch(POST) to express server fails. The server does not receive the request from JS, but receives request from Postman

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))

Post request with node js

I'm trying to make a post request with node.js and when I try to run it, I get the data to show up in the console but noot the body of my HTML. In the console I get the error
app.js:4 POST http://localhost:8000/addAnimal net::ERR_EMPTY_RESPONSE
postData # app.js:4
(anonymous) # app.js:25
app.js:21 Uncaught (in promise) TypeError: Failed to fetch
It seems like the function is working but not the actual post request part. I can't for the life of me figure out what I'm doing wrong.
This is my code:
server.js:
projectData = {};
/* Express to run server and routes */
const express = require('express');
/* Start up an instance of app */
const app = express();
/* Dependencies */
const bodyParser = require('body-parser')
/* Middleware*/
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const cors = require('cors');
app.use(cors());
/* Initialize the main project folder*/
app.use(express.static('project1'));
const port = 8000;
/* Spin up the server*/
const server = app.listen(port, listening);
function listening(){
// console.log(server);
console.log(`running on localhost: ${port}`);
};
// GET route
app.get('/all', sendData);
function sendData (request, response) {
response.send(projectData);
};
// POST route
app.post('/add', callBack);
function callBack(req,res){
res.send('POST received');
}
// POST an animal
const data = [];
// TODO-Call Function
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body)
})
app.js
/* Function to POST data */
const postData = async ( url = '', data = {})=>{
console.log(data);
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
const newData = await response.json()
// console.log(newData);
return newData.json()
}catch(error) {
console.log("error", error)
// appropriately handle the error
};
};
// TODO-Call Function
postData('/addAnimal', {animal:'lion'});
Any help would be greatly appreciated.
Thanks,
Mike
💡 The only one reason why you got message like it, it's because you never send response to the client.
👨‍🏫 So, You should to send response to the client. For an example, you can look at this code below: 👇
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body);
// send data to client
// you can change req.body with the object what you want to sent do the client
res.status(200).send(req.body);
})
📤 Update: Addtional information
Make sure you call the endpoint: http://localhost:8000/addAnimal.
Frontend: Make sure your code like this code below
const postData = async ( url = '', data = {})=>{
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
console.log(await response.json());
return await response.json()
}catch(error) {
console.log("error", error);
};
};
I hope it can help you 🙏.
Try this:
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body);
res.send('done'); // send response
});
Change the app.js code with the below.
/* Function to POST data */
const postData = async (url = "", data = {}) => {
const response = await fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
try {
return response.json();
} catch (error) {
console.log("error", error);
// appropriately handle the error
}
};
// TODO-Call Function
(async function(){
let res = await postData("/addAnimal", { animal: "lion" });
console.log(res);
})();
And also change the post method like below.
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body);
res.status(200).send(data);
})

How do I send a request from One Nodejs application to another using an IP address?

I have 2 Nodejs Server running. One of the server just has a post route:
app.post("/",(req,res)=>{
console.log(`Someone sent a post request`)
})
This server is running on localhost:9000. How do I fire the post route from a different Nodejs Server?
You could try something similar to this:
var request = require("request");
app.post("/", (req, res) => {
var options = {
method: 'POST',
url: 'http://localhost:9000/employee',
headers: { 'Content-Type': 'application/json' },
body: { id: 1 },
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
// Process the body and return the response.
return res.send(body);
});
});
Additional link

Chunked base64 string, piece by piece using http nodejs

From my API(nodejs), I'm accessing a third-party API (using http) to download files.
The service returns a Base64 string, chopped into smaller pieces, to be able to handle larger files.
Is it possible to do multiple http-requests (loop ?) to the third-party service, send each piece in response, to the browser until there is no longer any response from the third-party service?
The reason i want to do this, is because I don't want to consume to much memory on the node server.
I will put the pieces back together in the browser.
Any suggestions on how to do this?
See my current code below.
var request = require('request');
router.post('/getfiledata', function(req, res) {
var fileid = req.body.fileid;
var token = req.headers.authorization;
getFileData(req, res, dbconfig, fileid, token, function(err, chunkOfFile) {
if (err) {
res.status(500).send({
status: 500,
message: err
});
return;
}
res.send(chunkOfFile);
});
});
function getFileData(req, res, dbconfig, fileid, token, next) {
var url ="http://*ip*/service/rest/getfiledata";
var reqbody = {
fileId: fileid
};
var options = {
url: url,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': token
},
json: true,
body: reqbody
};
/*SOME LOOP HERE TO GET EACH CHUNK AND SEND TO BROWSER*/
request(options, function(err, resp, body) {
if (err) {
console.log(err);
next(err, undefined);
return;
} else {
next(undefined, body)
};
});
};
I think you need Socket.io to push chunks to the browser.
Server :
socket.send("chunk", chunkOfFile)
Client :
let fullString = ""
socket.on("chunk", chunkOfFile => fullString += chunkOfFile )
Something like that
The request library you are using allows for streaming of data from one source to another. Check out the documentation on github.
Here is an example from that page:
request
.get(source)
.on('response', function(response) {
console.log(response.statusCode) // 200
console.log(response.headers['content-type']) // 'image/png'
})
.pipe(request.put(destination))
You may choose to use the http module from Nodejs, as it implements the EventEmitter class too.
I ended up doing a recursive loop from the client. Sending http-requests to my API(node) until the response no longer returns any base64 data chunks.
Thank you guys!

Categories

Resources