Newbie question while trying to understand code created by others. Believe me I tried to understand this. Here goes..
For what reason would someone still call functions like .qs() and .json() in Request - module after we got what we need with .post() and sent the response already. They can't affect the request.post as they are called afterwards, can they?
With my skills I'm not able to understand from response module API docs (v2.22.0) what these actually do.
This is not the whole code but I tried to get the important parts here:
// When request comes to /getthisapge, make external query and return data in JSON format.
var request = require('request');
module.exports = function(app) {
app.get('/getthispage', function(req, res, next) {
var filter = {};
var query = {};
filter.category = req.query.category;
query.onBehalf = req.query.onBehalf;
request.post(URIandoptions, function(error, response, body) {
res.json(body.members)
}).qs(query).json(filter);
}
}
Without knowing exactly what the post function does (unnecessary to your question), you need to look at the order of execution.
request.post(URIandoptions, function (error, response, body){
res.json(body.members)
})
.qs(query) // ?
.json(filter); // ?
The function passed into post() does not get called at that specific moment. It is given to the post() function to do with as it pleases. This means technically that the function may never be called (depends on the api).
qs() and json() both get called upon the returning of the prior function. Usually this type of api means the following:
call post(), passing in a function to be run on completion
call qs() to setup the query details
call json() to tell the post function how to act, which in turn executes the actual post, running the completion function after data has been retrieved.
Related
I'm using node.js simply so that I can run scheduled tasks and use GET requests. I'll paste some code that displays what I want to do, although it doesn't work for an obvious reason:
const http = require("http");
const request = require("request");
http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type": "text/html"});
res.write("Hello, World!");
let a = getRequest();
console.log(a);
res.end();
}).listen(8080);
function getRequest() {
let b;
request("http://www.google.com", function(err, res, body) {
b = body;
})
return b;
}
So the b from the body does not work due to how the request is asynchronous and this leaves b as undefined when it is eventually printed. I know the way these callback functions are supposed to be used is to keep chaining of the callback function since that's the only place where the contents of body can be accessed. However, I don't want to keep chaining off functions because it completely destroys the structure of the program. I want to keep all my node server commands inside the http.createServer block. I don't want to place them in functions called from inside the callback function. In this example it doesn't really make sense for the process to be asynchronous since there's only 1 get request anyway and it can't be displayed in console.log until it's received anyway.
I just need a simple way to scrape data with get requests. What would be perfect is if I had some function that I could give a bunch of links, it gets the raw html from them, and then it waits for them to all be done so that I can process all the data at once.
How can something like this be implemented in Node.js?
You can do that using this module: sync-request.
With this module you will be able to make synchronous web requests from your NodeJS code.
Ok look at this code..
var http = require('http');
var handleRequest = function (request, response){
response.writeHead(200,{"context-type":"text/plain"});
response.end('Welcome to the node club! :)');
}
//the createServer method... creates a server WOW!
http.createServer(handleRequest).listen(8888);
console.log('The servers are running and the bacon is stopping');
It seems simple enough, the handleRequest function will create a writeHead function when the node will allow me to respond ...right? And if that is the case, I will be able to write out "Welcome to the node club" in the end method. The thing I don't understand about node is the request variable or object or whatever. In the function am I requesting the node? Or is the node requesting me to run a function? I'm not using the request variable in the function so would it still run if I left it out?
The argument to http.createServer is a function to be called on each request. The function is documented as
function (request, response) { }
request is an instance of http.IncomingMessage and response is an instance of http.ServerResponse.
What you do in this function is up to you; it can be anything.
However, virtually all web applications end up writing an answer to the client, and that's done via the response object. Also, since an application that serves just one page is quite limited, most applications also want to get information from the HTTP request, including the path requested (something like '/questions/37265770/so-about-requesting-in-node-js', in request.path), HTTP POST parameters and the like.
Your function gets called with two arguments, the first of which is the request object, the second the response object. There is no magic involved - you seem to call magic "node", but that's just the name of the project.
I have a get call and a post call in my node.js file, both of which use the same variable that I initialized to an empty string outside these calls. In the post call, I set the variable, while in the get call, I return the value of the variable to my clientside angularjs that is requesting the value. In my angularjs file, I make the post call first and then the get call, which means the value should be set and should be available when the get call is issued and returns. Here's what I'm doing:
NodeJS
var myUrl= "";
app.post('/post', function(req, res){
myUrl = res.url;
});
app.get('/get, function(req, res){
res.json({result: myUrl});
});
AngularJS:
var promise = $http.post('/post')
.then(function(response){
return $http.get('/get');
}).then(function(response){
console.log(response.data.result);
});
I've tried AngularJS promise chain calling but it still doesn't work. The problem I'm having is that when I make the get call in the first round of requests, the url variable hasn't been set yet even though the post call has been already issued, so the get call returns an empty string. In the second round of requests, the get call returns the value that has been set from the first post call, and so on and so forth.
Any ideas on why this is happening and suggestions on how to solve this issue so that the get call returns the value that is set in the post call in the same round of requests (the get call is issued when the post call is done)? I'm fairly new to NodeJS so any help is appreciated!
Your angular code is fine, though you have missed a small thing. I modified your code and tested, it works as expected.
Solution:
var myUrl= "";
app.post('/post', function(req, res){
//not res.url
myUrl = req.url;
//Your missed this!
res.status(204).end();
});
app.get('/get, function(req, res){
res.json({result: myUrl});
});
Explanation:
Without res.status(204).end(); or res.send({}) or res.json({}) the /post call just updates the url and then hangs there and does nothing, never returns and will eventually timeout. So when next time you call /get you get the URL.
You must consider the fact that all your route handlers are just middleware and you must generate a response or execute next middleware.
In your case, you wanna handle the request and want to end there, it was required to send some response. so we sent res.status(204).end();, meaning: There is no content to serve
Hope this helps!
I understand that out of the box Express isn't an MVC framework, however I'm trying to set it up like one.
I've used other similar frameworks in PHP like Laravel where in a route in you can use a controller like
Route::get('user/profile', 'UserController#showProfile');
Which will run all the code in the showProfile method in the UserController class,
so my question is, how would I achieve the same thing or something similar using Express?
I'm using Node 5 and writing the code in ECMAScript 6.
Currently I have a class I want to use as the controller and a method I want to return the data, I'm able to log the data to the console when a user navigates to the route but haven't figured out how to send it back as the response.
If you dive into the documentation, you'll find that the "controller methods" you refer to need to conform to a specific signature. Namely, they receive (at least) the request and response representations.
If you have already created a router, this will be a rough equivalent to the PHP you posted:
router.get('user/profile', userController.showProfile)
Your showProfile "method" needs to have this signature:
const userController = {
showProfile(req, res) { /*...*/}
}
I put "method" in quotes because express won't call it as a method unless you explicitly bind it to the controller object. We're passing it as an unbound function here. If you wanted to use it as a method (to have access to the controller as this), pass userController.showProfile.bind(userController) to router.get†.
But for now let's stick to those req and res parameters of the showProfile handler (that's the proper name). req represents the HTTP request, you can get headers, request payload and other stuff from it. res is the HTTP response that will be sent. So you can use it to set an HTTP status code, send body data and so on.
For illustrative purposes, let's assume you can get your user profile synchronously by calling userController.getProfile(id). And let's assume that, by some mechanism, a property userId is set on the request that is the currently authenticated user's ID.
const userController = {
showProfile(req, res) {
// We call some code to get what we want to send back
const profile = userController.getProfile(req.userId)
// We send it in the response as JSON
res.send(profile)
}
}
res.json will JSON.stringify the profile and send it as response payload.
How do you get req.userId set, you ask? Well, this is just an example, but you can achieve similar results by using middleware. A middleware is simply a handler that does something and then lets other handlers continue processing the request. But again, there's plenty to read from the docs.
† It's usually not necessary though, since controllers tend to be singletons. You can simply access its properties by doing userController.otherProperty. Of course, you don't even need to define a handler as a method of a controller object, it can be a function that stands on its own.
I did something like this
usercontroller.js
class UserController() {
constructor() {
this.users = ['user1', 'user2'];
}
getUsers(req, res) {
res.status(200).json(this.users);
}
}
//router.js
const port = 3000;
const app = express();
const _invoke = function(controller) {
return function(req, res) {
const [controllerClass, method] = controller.split('#')
const className = require(controllerClass)
const obj = new className
obj[method](req, res)
}
}
app.get('/get-users',
_invoke('./controllers/UserController#getUsers'));
app.listen(port);
I am very new to Node.js and how it's callbacks work exactly, I am trying to find some good documentation on it but it's just not clicking for me yet. I'm coming from python so I'll show an example of what I'm use to doing in python, I'm not sure if it's possible in node though
def getRequest(link):
url = urllib.request.urlopen(link).read().decode()
return url
class urlData:
def __init__(self, link):
self.results = getRequest(link)
I'm not sure if node can do this because it's async ways, or is it possible? I'm not sure how to go about this the correct way, how would I replicate this action in node? If not can the this code be toyed with to get similar results, a way to set the variable with the data that is going to come?
The way you might do this in node is the following:
Install Request. https://github.com/mikeal/request
var request = require('request');
Now we have a simple http client.
var data;
request.get({url:url, json:true}, function (e, r, body) {
// this will get called when the response returns. Your app will continue before this is called.
data = body; // i have no idea what you want to do with it
console.log(body); // should be json
})