The current code provides me with the data based on id of the API. My idea is to create a search based on keyword for it.
The idea is when you search for 'coding', it should log the data/posts with the keyword as a title.
function script(id) {
request(`https://hacker-news.firebaseio.com/v0/item/${id}.json`, function (error, res, body) {
if (error) {
console.log(error);
} else {
let myData = (JSON.parse(body))
var titleUrl = `https://news.ycombinator.com/item?id=${myData.id}`;
request(titleUrl, function (err, res, body) {
console.log(myData.title);
console.log(myData.score)
console.log(titleUrl)
});
}
});
}
script(23202120);
The second request does not return json instead it returns a html-page. You can use a html-parser like https://github.com/cheeriojs/cheerio to actually read the contents of the page.
...
request(titleUrl, function (err, res, body) {
const $ = cheerio.load(body);
const title = $('title');
console.log(title);
...
});
...
Related
I am currently developing a website with an API that I built with node.js, express and MongoDb for the database.
I am curretly learning node and express and cant find my way to create a middleware to verify that the USER ID matches the POSTED BY ID from a COMMENT. That way the USER can only delete his own comments.
My middleware looks like this
verifyUserIdPostedBy.js
const Comment = require('../models/Comment');
var userId
var postedById
module.exports = {
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
});
console.log(userId);
if(userId !== req.postedById)
return res.status(500).json({message: 'Stopped'})
return next();
},
}
My console.log() in the middleware show me exactly the 2 values that I want to compare but I get the error 'Stopped' and my verification never happens. I tried accesing the route with the comment owner and also with not the comment owner and none works
and my route looks like this
comments.js
const express = require('express');
const router = express.Router();
const Comment = require('../models/Comment');
const verify = require('./verifyToken');
const {verfyUserIdPostedBy} = require('./verfyUserIdPostedBy')
// DELETE COMMENT
router.delete('/:commentId', verify, verfyUserIdPostedBy, async (req, res) => {
try {
const removedComment = await Comment.deleteOne({ _id: req.params.commentId });
res.json(removedComment);
} catch(err){
res.json({message:err});
}
})
Like I said I am new at this but cant find a way to do it properly.
Appretiate in advance any help and advice.
Mario
I add comments in your code to explain how it works :
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
/* -----this is a callback function------ */
/* the code inside the callback function is executed only when findOne finish and **after** the code outside */
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
});
/* this code is executed before the code inside the callback function */
console.log(req.postedById); // undefined, you can check
console.log(userId);
if(userId !== req.postedById) // this is always true
return res.status(500).json({message: 'Stopped'}) // and this line always executes
return next(); // and this line never execute
},
The concept is callback. I strongly advise you to research this keyword, callback is used massively in NodeJS. Nowadays, there are Promise and async/await that allow developers to write asynchronous code in a "synchronous way", but callback is the base.
In order for your code works, 1 simple solution (there are many solutions!) is put comparison code into the callback block, something like :
const Comment = require('../models/Comment');
var userId
var postedById
module.exports = {
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
console.log(userId);
if(userId !== req.postedById)
return res.status(500).json({message: 'Stopped'})
return next();
});
},
}
I want to access the variable "result" from the function which contains the query.
When I want to access it from another file, in which I am trying to work with the output after a POST Request, the variable is declared as "undefined".
This is the file in which i execute the query:
const db = require('../db/connect');
module.exports = {
getID(name){
db.query(`SELECT CWID FROM user WHERE surname = '${name}'`, function(error, result, fields){
if(error) console.log(error);
console.log(result);
});
}
}
And this is the file where I want to work with the data:
router.post('/test', function(req, res){
const data = queries.getID(req.body.name);
console.log(data);
res.render('new test', {title: "test"});
})
Can anybody help me with this?
Here's an example of querying using mysql and async/await. This should do what you would like:
Query file
const db = require('./db/connect');
module.exports = {
getID(name) {
return new Promise((resolve, reject) => {
db.query(`SELECT CWID FROM user WHERE surname = '${name}'`, function(error, result, fields) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
}
Main File
router.post('/test', async function(req, res){
const data = await queries.getID(req.body.name);
console.log("Query result: ", data);
res.render('new test', {title: "test"});
});
The reason your result is undefined in your initial example is that you're using asynchronous i/o (normal in Node.js). By returning a Promise from getID, we can make async. calls easily and with some nice code syntax.
I am simply trying to output a single value (thumbnail) of an XML file in Node.js. I feel like I am so close but can't figure it out.
var request = require('request');
request('https://boardgamegeek.com/xmlapi/game/1', (error, response, body) => {
if (error) { return console.log(error); }
console.log(body.thumbnail);
});
You need a XML parser, for example xml2js :
var request = require('request');
var parseString = require('xml2js').parseString;
request('https://boardgamegeek.com/xmlapi/game/1', (error, response, body) => {
if (error) { return console.log(error); }
parseString(body, function (err, result) {
console.dir(result);
});
});
Double check by using the console to see all of body I.e:
console.log(body)
Then you will see the options you have available. Show us what you get and we could be more specific or it may be enough for you to work out at a glance. You are on the right track. It just depends on the data structure that is there for you.
I feel like a complete moron but me and a friend are working on a project together and having trouble getting the first route to return the items requested from the Etsy API and have getAllListings add the items to the database. If you can see something glaringly obvious that we are doing wrong please let me know.
I should also mention that while the statement console.dir(body) does print out the items to the terminal it does not look like the contents are being passed to GET '/api/etsy/getListings'
Thanks!
routes.js
//this i want to return a list of active listings from the users shop.
app.get('/api/etsy/getListings',function(req, res){
bEtsy.getAllListings(req, res, function(err, body) {
});
res.json(req.body);
});
bEtsy.js
var standardCallback = function (err, status, body, headers, callback) {
if (err) {
console.log(err);
return callback(err, null);
}
if (body) {
console.dir(body);
return callback(null, body); // this gives me an error
}
}
var getAllListings = function(itemId, callback){
var Item = mongoose.model('Item');
var listingsParams = {
include_private: true
}
etsy.auth().get(
'/shops/'+etsy.shop+'/listings/active',
listingsParams,
function(err, status, body, headers){
var newi = new Item({name: body.title, stock: body.count, owner: "00000000000000000000",
etsy:{listingId: body.listing_id, stock: body.count}});
newi.save(function(err){
if (err) return handError(err);
});
standardCallback(err, status, body, headers, callback);
}
);
};
You are calling this function with three parameters, when it only takes two
bEtsy.getAllListings(req, res, function(err, body) {
});
On top of that the first argument itemId is being passed the request object and then it is also never used inside the function itself but some global variable called listingsParams is?!?
Suppose I have a CMS application written in Node.js which persists data on a Redis database. When this application creates a new content, it should increment the id counter, add the new id to a list of ides and then set a new hash with content. What I would do for now is to create a function to perform this execution. This function (let us call it createArticle()) would have a callback and would execute the increment. Once the increment was executed, a callback function would push it into the list of ids. After that, another callback would create the hash. The hash-creating callback would call the function passed as parameter to createArticle():
function createArticle(title, content, callback) {
var client = redis.createClient();
client.incr("idCounter", function(err, id) {
if (err) return callback(err, data);
client.lpush("articleIds", id, function (err, data) {
if (err) return callback(err, data);
var key = "article:"+id;
client.hmset(key, "title", title, "content", content, callback);
});
});
}
I would use this function more or less this way (using Express in this example):
app.post('/createarticle', function(req, res) {
var title = req.body.article.title,
content = req.body.article.content;
createArticle(title, content, function(err, data) {
if (err) return res.render('error', { status: 500, message: 'Internal Server Error' });
res.render('index', { status: 200, message: 'Article created!' });
});
});
However, this code looks a bit cumbersome to me. Is this the way to go. Or is there a better way to do a series of I/O steps? I used Express and Redis in my example, but the answer do not need to use them.
You can make those error-catchers single-lined:
function createArticle(title, content, callback) {
var client = redis.createClient()
client.incr("idCounter", function(err, id) {
if (err) return callback(err, data)
client.lpush("articleIds", id, function (err, data) {
if (err) return callback(err, data)
var key = "article:"+id
client.hmset(key, "title", title, "content", content", callback)
})
})
}
And you could use a helper for handling errors:
function noError(errorCb, cb) {
var slice = Array.prototype.slice
return function (err) {
var currentCb = err ? errorCb : cb
currentCb.apply(this, slice.apply(arguments, err?0:1)
}
}
function createArticle(title, content, cb) {
var client = redis.createClient()
client.incr("idCounter", noError(cb, function(id) {
client.lpush("articleIds", id, noError(function (data) {
var key = "article:"+id
client.hmset(key, "title", title, "content", content", callback)
}))
})
}
Or something like that.