I'm using xml2js with node.js to retrieve data from an API, but I would only like the code to run when the "/testpage" route is activated, which would then assign the api response to a variable and pass it along to a script on testpage.ejs where the end goal is to print the object/variable contents to the console.
The problem I'm facing is that I'm getting the "undefined" browser console response with the above code.
If I place the code outside of the route, have the response assigned to a variable and then pass that variable to the testpage script, then it works fine.
At this point I'm assuming it could be an asynchronous issue, but I'm not sure, or even how to tackle it if so.
// Node.js
const requestPromise = require('request-promise'),
xml2js = require('xml2js').parseString,
express = require("express"),
app = express();
const port = 3200,
apiURL = 'https://api.exampleapi.com';
app.set("view engine", "ejs");
app.use('/public', express.static(__dirname + "/public"));
app.get("/testpage", function(req, res){
var myApiObject; // To store api response
requestPromise.post(apiURL, (error, response, body) => {
if(error){
console.log(error);
return error;
}
}).then( (body) => {
xml2js(body, (err, result) => {
if(err){
console.log(err);
} else {
myApiObject = result;
return result;
}
});
});
res.render("testpage", {myApiObject: myApiObject});
});
app.listen(process.env.PORT || port, function(){
console.log("Server is running...");
});
<!--testpage.ejs-->
<html>
<head>
<title>
</title>
</head>
<body>
<p>This is the testpage</p>
<script>
var myObj =<%-JSON.stringify(myApiObject)%>
console.log(myObj);
</script>
</body>
Any ideas on what I'm doing wrong?
You need to render your page after the response from API call is received. Change your code like this:
requestPromise.post(apiURL, (error, response, body) => {
if(error){
console.log(error);
return error;
}
}).then( (body) => {
xml2js(body, (err, result) => {
if(err){
console.log(err);
} else {
res.render("testpage", {myApiObject: result});
return result;
}
});
});
Related
i am new to node.js and want to create api for getting data and update that data on frontend,please give me solution for this,i am getting data from this code but unable to update data.I am using react js for frontend.
var express = require("express");
var app = express();
var oracledb = require('oracledb');
var dbconfig= require('./dbconfig')
(async function () {
let connection
try {
connection = await oracledb.getConnection({
user: 'dbconfig.user',
password: 'dbconfig.password',
connectString: 'dbconfig.connectstring'
});
var result = await connection.execute('select * from
PROPERTY.app_booklet_challan_detail', []);
console.log("Successfully connected to Oracle!")
console.log(result)
} catch (err) {
console.log("Error: ", err);
} finally {
if (connection) {
try {
await connection.close()
} catch (err) {
console.log("Error when executing the database connection: ", err);
}
}
}
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
next();
});
app.get('/list', (req, res, next) => {
res.send(result);
next()
});
app.put('/list/update', (req, res, next) => {
let STATUS=res.data
connection.execute('UPDATE PROPERTY.app_booklet_challan_detail SET STATUS= ? WHERE
BOOKLETID= ? ', [STATUS])
res.send(STATUS)
next()
})
app.listen(3001, function () {
console.log("Started on PORT 3001");
})
})()
Your question is a little broad to answer with code, but I've written an entire series on this topic: https://jsao.io/2018/03/creating-a-rest-api-with-node-js-and-oracle-database/
Note there are links to a GitHub repo with the code from each module.
Once you finish with the series you should be able to take things in the direction that makes the most sense for your project.
I need to fetch foo from the query below:
exports.get = function(id, cb) {
sql = 'SELECT `sidebar`, `test` FROM users WHERE `id` = "' + id + '"';
con.query(sql, function(err, foo) {
if (err) { return cb(err) }
else { return cb(foo) };
});
}
Then render foo on my app.js like this:
app.get('/dashboard', ensureLoggedIn('/login'),
function(req, res) {
const id = req.session.passport.user;
const foo = db.defaults.set(id) //db.defaults.set calls the query
console.log(foo); //prints undefined
res.render('dashboard', { foo:foo });
});
This was my latest attempt:
app.get('/dashboard', ensureLoggedIn('/login'),
function(req, res, next) {
const id = req.session.passport.user;
db.defaults.get(id, function(err, foo) {
if (err) return next(err);
res.render('dashboard', {foo:foo});
//also tried:
//return res.render('dashboard', {foo:foo});
});
The attempt above doesn't render the page at all. The html loads as:
[object object]
What am I missing?
You're trying to render server side a template asynchronously (after fetching the data) and you can't do that.
What you can do is send synchronously the template to the client and then expose an endpoint to fetch those data and modify the page accordingly (on the client).
app.get('/dashboard', ensureLoggedIn('/login'), function(req, res) {
res.render('dashboard');
});
app.get('/fetchdata', function (req, res, next) {
const id = req.session.passport.user;
db.defaults.get(id, function(err, foo) {
if (err) return next(err);
res.send(foo);
});
})
I am trying to write a small API logger as an Express middleware. The logger collects various pieces of information from the req and res, then saves a JSON file to disk that can be read later.
This is my current function to store the logs.
function store(req, res, next) {
init();
const log = {
request_url: req.hostname,
request_body: req.body,
request_method: req.method,
request_headers: req.headers,
api_endpoint: req.baseUrl,
timestamp: moment().format('x')
};
res.on('finish', () => {
log.response_body = res.body;
log.response_status = res.statusCode;
global.enoch_logs.push(log);
fs.writeFile(`./logs/${ moment().format('x') }.json`, JSON.stringify(log), (err) => (err) ? console.log(err) : null);
});
next();
}
The problem is that res.body is always empty. I have tried a few different methods to capture the response body but nothing seems to work.
Where am I going wrong?
I am serving a static webpage from Node.JS via Express webserver:
app.use('/', express.static('public'));
What is the most minimalistic way to integrate some dynamic content, e.g. a list of items that is retrieved from a database into such a page?
I see the possibility to "fake" a .js file on the server that is actually dynamically created and then loaded in an index.html that resides inside the public folder on the server:
app.get('/myScript.js', (req, res) => {
data = getDataFromDatabase();
res.send('var data1 = ' + data[0] + '; var data2 = ' + data[1]);
});
This seems extremely hacky and I wonder what the best minimalistic approach to this is.
You can also return a response from a callback inside of your get route. I do something like this:
Endpoint:
router.get('/people', (req, res) => {
People.list((error, response) => {
if (error) return res.end();
return res.send(response);
});
});
Model:
module.exports = {
connect: (callback) => {
r.connect({
host: config.db.host,
port: config.db.port,
db: config.db.name
})
.then((connection) => {
return callback(null, connection);
})
.error((err) => {
return callback(err);
});
},
list: function (callback) {
this.connect((err, connection) => {
if (err) return callback(err);
r.db(config.db.name).table(config.db.tables.people)
.run(connection)
.then((cursor) => {
return cursor.toArray();
})
.then((users) => {
return callback(null, users);
})
.error((err) => {
return callback(err);
});
});
},
...
With this then I get the response object printed to my screen. The model code is rethinkdb code, but you can substitute that with whatever you are using. Sorry if this wasn't quite what you were after. Best of luck with your build =)
I have a route I that in order to get all the data needs to access the API server multiple times (according to the data that was given).
Now I need to add a third access to the server and it's getting rather unreadable.
The following code is working, but I have a feeling I'm not doing it right (promises?) - couldn't figure out what exactly is recommended in this case
The code: (stripped down to emphasise the point)
router.get('/', function(req, main_response) {
http.get(FIRST_API_COMMAND, function (res) {
var moment_respose_content = '';
res.on("data", function (chunk) {
moment_respose_content += chunk;
});
res.on('end',function(){
if (res.statusCode < 200 || res.statusCode > 299) {
main_response.send('error in getting moment');
return;
}
var response = JSON.parse(moment_respose_content );
if (response.success)
{
var data = response.data;
//doing something with the data
http.get(SECOND_API_COMMAND, function (res) {
res.on("data", function (chunk) {
comment_respose_content += chunk;
});
res.on('end',function(){
var response = JSON.parse(comment_respose_content);
if (response.success)
{
var comments = response.data;
main_response.render('the page', {data: data});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting comments');
});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting moment');
});
});
You can write a middleware for each remote action, and then use those middlewares before the get handler, so the get handler can simply access their results. (Promises can help if you need to start subsequent requests before waiting for earlier ones to finish, but that situation is rare.)
For example, using express middleware to fetch each remote data independently:
var request = require('request');
var express = require('express');
var app = express();
var router = express.Router();
/* middleware to fetch moment. will only run for requests that `router` handles. */
router.use(function(req, res, next){
var api_url = 'https://google.com/';
request.get(api_url, function(err, response, body) {
if (err) {
return next(err);
}
req.moment_response = response.headers["date"];
next();
});
});
/* middleware to fetch comment after moment has been fetched */
router.use(function(req, res, next){
var api_url = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
request.get(api_url, function(err, response, body){
if (err) {
return next(err);
}
req.comment_response = parseInt(body);
next();
});
});
/* main get handler: expects data to already be loaded */
router.get('/', function(req, res){
res.json({
moment: req.moment_response,
comment: req.comment_response
});
});
/* error handler: will run if any middleware called next() with an argument */
router.use(function(error, req, res, next){
res.status(500);
res.send("Error: " + error.toString());
});
app.use('/endpoint', router);
app.listen(8000);
Often the remote data you want to fetch is based on some parameter of the main request. In this case you would want to use req.param() instead of App.use() to define the data-loading middleware.