i can't figure out why we are using response.on - javascript

I've written a code here and I want to know what "response.on" is doing and why we are passing "data", what is this "data".
what exactly that ".on" is used for.
const express = require("express");
const https = require("https");
const app = express();
app.get("/",function(req,res){
const url="https://api.openweathermap.org/data/2.5/weather?q=London&appid=5c8618a9210a11846accc217f3b3084f";
https.get(url,function(respons){
response.on("data",function(data){
const wht = JSON.parse(data)
temp = wht.main.temp
res.send("temp "+ temp)
})
})
})
app.listen(3000, function(){
console.log("running");
});

.on("nameOfEvent", callback) it's a event emitter. So, basically whenever that event is called, that callback will be executed. data is just the name of the event.

In your code there is bug.
You using respons in the argument of function and response inside of function.
Waiting on data of response is documented in https
https://nodejs.org/api/https.html#https_https_get_options_callback
You can read that response is not a classical response from the server but an event listener that listens for stream of data.
It is a low-level interface and in your applications, you should not use them. Lets interest in node-fetch or axios instead if you want only get a response, but not process streams in real-time.

Related

Cannot execute HTTP GET call twice on nodejs/express backend

Using the packages express and ````ftp``` I try to simply get files from an ftp and return
them by HTTP GET to the client requesting.
The first request goes through fine, but when I try calling it again I run into Exception:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I've tried to use the solutions from Error: Can't set headers after they are sent to the client like having a return when sending, not setting , unfortunately none of the worked for me.
This is ALL the code:
const express = require('express');
const ftp = require('ftp');
const app = express();
const port = 3000;
const c = new ftp();
app.get('/files', (req, res) => {
c.on('ready', () => {
c.list((err, list) => {
c.end();
return res.setHeader("Content-Type", "application/json").status(200).send({data: list});
});
});
c.connect({
host: 'xxx',
user: 'xxx',
password: 'xxx',
});
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
I think it might be something with the c.list() callback, however I cannot for the love of god find what is wrong with it, as the res.send() does not get called twice anytime.
The problem is you have just one ftp object, and every request subscribes to (and never unsubscribes from) the ready event, and the ready event fires every time you call connect() , which you do for every request. So when the second request calls connect(), the event fires for both the first and second request. This leads to setHeader() being called a second time for the first request, hence the error.
Using once() instead of on() so that the event handler it only called once should resolve the issue, though there are probably better ways to write this code (use a promise API or promisify this one, only initialize a connection to the FTP server once instead of for every request).

https api request is not working with https.get(url)

I need to pull the weather API data from
https://api.weatherapi.com/v1/current.json?key=f5f45b956fc64a2482370828211902&q=London
It gives a response when pasted in the web browser as well as in postman. But, once incorporated in javascript https.get it fails by continuously loading the browsers and hanging the terminal with unwanted informations.
app.js :
//jshint esversion:6
const express = require("express");
const https = require("https");
const app = express();
app.get("/",function(req, res){
const url = "https://api.weatherapi.com/v1/current.json?key=f5f45b956fc64a2482370828211902&q=London";
https.get(url,function(response){
//console.log(response);
response.on("data",function(data){
const weatherData = JSON.parse(data);
const temp = weatherData.current.temp_c;
const weatherDescription = weatherData.current.condition.text;
});
});
res.send("Server is up and running");
});
app.listen(3000, function(){
console.log("Started on port 3000");
});
I tried the specific request that you posted using https.get() and it worked for me. So it will be difficult to figure out what is the exact problem without more information, for example about how exactly it is failing for you. What messages are you seeing on the console? How are you accessing the result of the request, so what makes you think that the request didn't work?
But apart from that, that is not how you usually make requests in Node. The "data" event may be emitted multiple times if the response arrives in multiple chunks, so the way you do it will only work if you are lucky and the response arrives in a single chunk. The proper way to do this by hand would be to listen to all "data" events, concatenate the result, and then when the "end" event is emitted, parse the concatenated data. However, it is rather uncommon to do this by hand.
A more common way to do this would be to use a library such as node-fetch to make the request for you. For example like this: fetch(url).then((res) => res.json()).then((weatherData) => { const weatherDescription = weatherData.current.condition.text; }).

How can I receive data using socket.io?

I am running a server using expressjs. Whenever a user accesses to one of my specific url (for this purpose, just imagine it will be https://server.com/test), I want to emit a data to another webserver using socketio, listen to the data and respond to the user with the data I have received.
Few things to note:
My server expects nothing but just an access to the https://server.com/test url.
Another server, which I want to connect using socket.io and obtain data expects me to send an argument of {"got" : "true"} to parameter called "test".
When another server receives the socket emit from my server on parameter "test" with arguments specified above, it simply replies back with an argument {"message" : "true"}
My code is quite simple and looks like this (router) :
const express = require("express");
const router = express.Router();
//const Goal = require("../models/battery_message");
const mongoose = require("mongoose");
const io = require("socket.io-client");
const host = "https://another_server.com"
const socket = io(host, {query:"email=edmund#gmail.com"});
console.log("connected");
router.get('/', function(req,res) {
socket.emit("test_me", {"got" : "true"}, function(data){
exists = data;
console.log(data);
});
});
module.exports = router;
The problem I have is whenever the user accesses my server on https://server.com/test nothing happens, as no response comes like in an infinite loop. My guess is that I need some kind of another socket.emit because another server probably emits its response to the socket too, but I might be wrong.
So to sum up, my question is, what do I need to add in order to successfully get the response from another server?

Confused about how to get req.body

I cannot seem to get the body data shown on my server. I am actually trying to get this in post/put/fetch calls, but to try to fix the problem, i've boiled it down to a simple .get, and it still won't appear. Can anyone see why the body isn't showing on the server? I'm unable to get anything done in more complicated called due to this (like get the body of the req, but sticking to this simple example for now.)
This code is a fully working and sends data, just cant seem to access the body on the server.
server.js
const express = require('express');
const app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
const port = process.env.PORT || 8000;
const Cat = require('./Cat');
const Dog = require('./Dog');
app.route('/animals')
.get(function (req, res) {
console.log(req.body, 'req.body log'); //this returns {}
res.send({ Cat, Dog });
})
app.listen(port, () => console.log(`Listening on port ${port}`));
In react, if I call the following callApi() function, console.log shows the body data just fine on the front end, and the data can be used on the page.
client call
callApi = async () => {
const response = await fetch('/animals');
const body = await response.json();
console.log(body) //shows all the data just fine!
if (response.status !== 200) throw Error(body.message);
return body;
};
Using node 9 and express 4.
I think you're confusing the request and response objects. But aside from that, I'll explain where/how to get data passed in from GET and POST/PUT requests.
When a GET request is made, you can pass data to the server via query params (i.e. /animals?type=cat). These parameters will be available already parsed in an object called req.query.
When a POST or PUT request is made, and you've applied the body parsing middleware (which you have done), the JSON will be available as a parsed object under req.body.
In your example, you have made a GET request, and have no provided any query string parameters. So req.body will return an empty object, as will req.query.
Your client call shows data because you've sent data back in the response via res.send(). This is totally unrelated to why req.body is an empty object in your case.
Try using fetch('/animals?type=cat') in your client call. Then, you will see that req.query returns { type: 'cat' }.

How to know when node.js express server is up and ready to use

Have an application where I want to start a node express server and then start a browser on the same machine automatically as soon as the server is up. How can I query to see if the server is up and ready to go? I really wanted there to be some sort of callback on the .listen call, but doesn't seem to be. I could just wait a longer than I expect amount of time, but this is going on equipment that will be in the field so I either have to wait a ridiculous amount of time to make sure I'm up and running before kicking off the browser or have the user be smart enough to hit refresh if the page doesn't load right. Neither of those are good options for me. . .
I read the API online but don't see anything like this. Surely there's a trick I don't know that can accomplish this.
If the node HTTP api (which has a callback and tells me about the listening event) is the base for the express object, maybe there is a callback option for the express call listen that isn't documented. Or perhaps I'm supposed to just know that it's there.
Any help would be greatly appreciated.
The Express app.listen function does support a callback. It maps the arguments that you pass in to the http.listen call.
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
So you can just call: app.listen(port, callback);
Or you could use http.listen directly.
var app = require('express')(),
server = require('http').createServer(app);
server.listen(80, function() {
console.log('ready to go!');
});
You can fire a custom event after the server is started:
// server.js
const express = require('express');
const app = express();
modeule.export = app;
app.listen(3000, () => {
app.emit('listened', null)
});
In a separate module, the app can listen your custom event:
// custom.js
const server = require('server.js');
server.on('listened', function() {
console.log('The server is running!');
});
You can use the http.listen method which has a callback function that triggers once the server is ready:
http.createServer(app).listen(app.get('port'), function () {
console.log('Printed when ready!!!');
});
See the official reference at Node.js:
http://nodejs.org/api/all.html#all_server_listen_port_hostname_backlog_callback
http://nodejs.org/api/all.html#all_server_listen_path_callback_1
http://nodejs.org/api/all.html#all_server_listen_handle_callback_1
As many have mentioned, the listen function (on the express app or an http server, both support it), does support a callback and that will let your node process know when it is listening.
So if you plan to launch the browser from within your express app, do it there and you are good. However, if you are launching the express app from an external script and then want that external script to open the browser, the node callback doesn't really buy you anything.
Waiting for some magic string on stdout isn't really an improvement on just waiting for a good HTTP response. You may as well just use a try/backoff/timeout loop with curl until you get a successful response.
server.on('listening', function() {
resolve();//I added my own promise to help me await
});
The Listening event worked for me. Note I added my own Promise. I imagine you could obtain similar results without a promise by adding an entry point to this listener.
Note, I tried the more intuitive server.on('listen') and it didn't work. Running node 6.9.1
With async/await syntax, this can be done by wrapping the server startup in a promise, so you can wait for it to be started before running anything else:
import express from 'express';
import http from 'http';
const app = express();
let server: http.Server;
const startServer = async (): Promise<void> => {
return new Promise((resolve, _reject) => {
server = app.listen(3000, () => {
console.log('Express server started');
resolve();
});
});
};
await startServer();
// here the server is started and ready to accept requests

Categories