Execute a javascript till node server runs in NodeJS - javascript

I am using NodeJS. I am checking the response status of https://encrypted.google.com/ . I have a file in my project. Let's call it ,
status.js :-
var https = require('https');
https.get('https://encrypted.google.com/', function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
}).on('error', function(e) {
console.error(e);
});
Now, I also have server.js file and node is running through it.
node server.js
I want to execute the status.js till the nodeserver runs. That means, it should continously check the status of https://encrypted.google.com/. What is the recommended way to do this ?
server.js :-
const express = require('express');
const bodyParser = require('body-parser');
// create express app
const app = express();
// listen for requests
app.listen(3000, () => {
console.log("Server is listening on port 3000");
});

Use a setInterval and execute the code from status.js. When your status is resolved as you want it, clear the interval via clearInterval.

Ok. I think the adding an event emitter was a bit unnecessary. You can try this out. This is the typescript file. For javascript replace the imports with the respective require statements.
server.ts
import express from "express";
import http from 'http';
import { getHttpsRequests } from "./status";
//Create an http server with the express app
const app = express();
const server = new http.Server(app);
let interval;
// listen for requests
server.listen(4300);
server.on('listening', () => {
interval = setInterval(() => {
getHttpsRequests();
}, 1000);
});
//register a close event on server
server.on('close', () => {
console.log('closing server');
clearInterval(interval);
});
status.ts
var https = require('https');
export function getHttpsRequests() {
//your code goes here
https.get('https://encrypted.google.com/', function (res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.on('data', function (d) {
process.stdout.write(d);
});
}).on('error', function (e) {
console.error(e);
});
}

Related

My JSON.parse in app.js doesnt function properly

app.js:
const express = require("express");
const https = require("https");
const app = express();
const port = 3000;
app.get("/",function(req,res){
const url ="https://maps.googleapis.com/maps/api/geocode/jsonaddress=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY;
console.log(response.statusCode);
response.on("data",function(data){
var jatin=JSON.parse(data);
console.log(jatin);
})
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Error on Console
app.listen(3000,function(){ console.log("server started on port
3000"); })
server started on port 3000 200 undefined:26
"long_name"
SyntaxError: Unexpected end of JSON input
at JSON.parse ()
at IncomingMessage. (/home/jatin/Downloads/full_stack/Web-Development/maps/app.js:11:21)
at IncomingMessage.emit (events.js:189:13)
at IncomingMessage.Readable.read (_stream_readable.js:487:10)
at flow (_stream_readable.js:931:34)
at resume_ (_stream_readable.js:912:3)
at process._tickCallback (internal/process/next_tick.js:63:19) [nodemon] app crashed - waiting for file changes before starting
The output is visible when I run it on browser but on the console it throws an error.
For some reason JSON.parse() isn't working as expected.
I am trying to make a geocoding API call and in response, it gives me a JSON output...
which when I enter it as a URL on the browser the expected output is received
But when app.js is run on a node express server and when I hit my localhost:3000 I am getting the console error
Apparently the JSON.parse("data") is working but stops unexpectedly. Which leads to error.
You need to have your code to perform JSON.parse on end event instead, like this example form the documentation:
http.get('http://nodejs.org/dist/index.json', (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
res.resume();
return;
}
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
Notice that this is http.get, but it should be the same for https.get, so in your code the on('data') should be used to assemble the chunks before your perform JSON.parse() on it.
const express = require("express");
const https = require("https");
const app = express();
const port = 3000;
app.get("/", function(req, res) {
const url = "API_URL";
https.get(url, function(response) {
console.log(response.statusCode);
let body = "";
response.on("data", function(data) {
body += data;
});
response.on("end", function() {
console.log(JSON.parse(body));
});
});
res.end("End data response");
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
basically .on('end', callback') and .on('data', callback') are event listener to data receive and request end events, and to be able to handle your requests response in node when using http(s).get you have to attache an event listener on data event which is invoked every time your request receives a chunk of the request response, and once the request ended by the service the event end will be invoked stating that there is no more data from the server requested hence the request ended.
as stated in the documentation:
The callback must take care to consume the response data for reasons
stated in http.ClientRequest section.

Check url-redirection using axios in nodejs

I'm using axios for API calling in nodejs.
I want to check if "https://origin.com/?url=https://destination.com" this url is redirecting to "destination.com".
So which status/headers I can check in axios response.
What will be the condition to check if it goes to "destination.com"
var express = require('express');
const axios = require('axios');
var app = express();
app.get('/test', function (req, res) {
// Check if it redirects
axios.get('https://origin.com/?url=https://destination.com')
.then(response => {
console.log(response);
// Here I want to check if it redirects successfully to "destination.com"
if (condition) {
// Successfully redirected to "destination.com"
}
})
.catch(error => {
console.log(error);
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I think you should try to use https for api, then in the response header you can find that it direct to the "destination.com".
Https is much simple and easy to use.
const https = require('https');
https.get('https://encrypted.google.com/', (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
});
}).on('error', (e) => {
console.error(e);
});
You can find the redirect url under responseURL key,
get fetchedUrl by
const fetchedUrl = response.request.res.responseURL;
see this
Environment node: v8.9.4 axios: ^0.18.0

jest asynchronous test ignoring expect() function

server.js is a simple express.js file that uses jwt tokens. I currently want to test a simple route that will only return the string "Hello World" as shown below
app.get("/", (req, res) => {
res.send("Hello World");
});
The code below is my jest file that is using supertest to send the request along with the valid jwt token
const supertest = require("supertest");
let server, request;
const serverStart = new Promise(resolve => {
server = require("../server.js");
request = supertest(server);
server.on("app_started", () => {
resolve();
});
});
beforeAll(async () => {
await serverStart;
});
afterAll(() => {
server.close();
});
describe("When testing the server.js", () => {
it("Should connect successfully and be able to return a response", async () => {
const response = await request
.get("/")
.set("Authorization", `bearer ${process.env.AUTHTOKEN}`);
expect(response.text).toBe("Hello World");
console.log(response.text);
});
});
When running this jest (after it's timeout of 5 seconds) says Timeout - Async callback was not invoked within the 5000ms timeout specified however, the console.log that I have added after the expect function outputs "Hello World" to the console meaning the request is made and returns a value but it carriers on with the code but is just skipping the expect function
I've also tried this with done() and also using a then() but got the same error both times and I've console logged the time before and after the call and found it only takes a few milliseconds to return a value, so why does the expect not seem to complete the test?
Pretty sure your problem is the app_started event that you are listening to. I don't know where that event is documented. I think you should use listening instead. I'm going to make some assumptions about your server.js file.
The following test passes. I think your tests never actually start because you are listening for an event that will never be fired.
This is the server.js file that I am testing with:
const http = require("http");
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("hello");
});
const server = http.createServer(app);
server.listen(8081);
module.exports = server;
This is my test file server.test.js:
const supertest = require("supertest");
let server, request;
const serverStart = new Promise(resolve => {
server = require("./server.js");
request = supertest(server);
server.on("listening", () => resolve());
});
beforeAll(async () => {
await serverStart;
});
afterAll(() => {
server.close();
});
describe("server", () => {
it("should get hello", async () => {
const response = await request.get("/");
expect(response.text).toBe("hello");
});
});
User zero298 pointed out that the test was failing during the beforeAll() function because server.on() wasn't returning anything. In the end I wrote the promise inside the server.js which resolves after it has started and then exported this promise.
let server;
const serverStart = new Promise(resolve => {
server = app.listen(port, err => {
if (err) {
console.log(err);
}
console.log("Listening on port " + port);
resolve();
});
});
module.exports = app;
module.exports.close = () => server.close();
module.exports.serverStart = serverStart;
and the beforeAll() in server.test.js now looks like
const server = require("../server.js");
let request;
beforeAll(async () => {
await server.serverStart;
request = supertest(server);
});

Travis tests returning undefined

I'm testing with jasmine and it's working fine locally. However Travis CI is returning undefined for all the API tests. Example
4) Server GET /api/v1/orders Status 200
Message:
Expected undefined to be 200.
Stack:
Error: Expected undefined to be 200.
at
Snippet from the tests
describe('GET /api/v1/orders', function () {
var data = {};
beforeAll(function (done) {
Request.get('http://localhost:3001/api/v1/orders', function (error, response, body) {
data.status = response.statusCode;
data.body = JSON.parse(body);
data.number = data.body.length;
done();
});
});
it('Status 200', function () {
expect(data.status).toBe(200);
});
it('It should return three Items', function () {
expect(data.number).toBe(3);
});
});
Could the problem be from the 'http://localhost:3001/api/v1/orders' URL?
You don't seem to be starting your server anywhere so localhost:3001 isn't available.
A good solution would be to use something like supertest. It would allow you to do something like so:
app.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const routes = require('./api/routes/routes.js')(app);
// We listen only if the file was called directly
if (require.main === module) {
const server = app.listen(3001, () => {
console.log('Listening on port %s...', server.address().port);
});
} else {
// If the file was required, we export our app
module.exports = app;
}
spec.routes.js
'use strict';
var request = require('supertest');
var app = require('../../app.js');
describe("Test the server", () => {
// We manually listen here
const server = app.listen();
// When all tests are done, we close the server
afterAll(() => {
server.close();
});
it("should return orders properly", async () => {
// If async/await isn't supported, use a callback
await request(server)
.get('/api/v1/orders')
.expect(res => {
expect(res.body.length).toBe(3);
expect(res.status).toBe(200);
});
});
});
Supertest allows you to make requests without relying on a specific port/url/other.

Simple Way to Implement Server Sent Events in Node.js?

I've looked around and it seems as if all the ways to implement SSEs in Node.js are through more complex code, but it seems like there should be an easier way to send and receive SSEs. Are there any APIs or modules that make this simpler?
Here is an express server that sends one Server-Sent Event (SSE) per second, counting down from 10 to 0:
const express = require('express')
const app = express()
app.use(express.static('public'))
app.get('/countdown', function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
})
countdown(res, 10)
})
function countdown(res, count) {
res.write("data: " + count + "\n\n")
if (count)
setTimeout(() => countdown(res, count-1), 1000)
else
res.end()
}
app.listen(3000, () => console.log('SSE app listening on port 3000!'))
Put the above code into a file (index.js) and run it: node index
Next, put the following HTML into a file (public/index.html):
<html>
<head>
<script>
if (!!window.EventSource) {
var source = new EventSource('/countdown')
source.addEventListener('message', function(e) {
document.getElementById('data').innerHTML = e.data
}, false)
source.addEventListener('open', function(e) {
document.getElementById('state').innerHTML = "Connected"
}, false)
source.addEventListener('error', function(e) {
const id_state = document.getElementById('state')
if (e.eventPhase == EventSource.CLOSED)
source.close()
if (e.target.readyState == EventSource.CLOSED) {
id_state.innerHTML = "Disconnected"
}
else if (e.target.readyState == EventSource.CONNECTING) {
id_state.innerHTML = "Connecting..."
}
}, false)
} else {
console.log("Your browser doesn't support SSE")
}
</script>
</head>
<body>
<h1>SSE: <span id="state"></span></h1>
<h3>Data: <span id="data"></span></h3>
</body>
</html>
In your browser, open localhost:3000 and watch the SSE countdown.
I'm adding a simple implementation of SSE here. It's just one Node.js file.
You can have a look at the result here: https://glossy-ox.glitch.me/
const http = require('http');
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
// Server-sent events endpoint
if (req.url === '/events') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
...(req.httpVersionMajor === 1 && { 'Connection': 'keep-alive' })
});
const refreshRate = 1000; // in milliseconds
return setInterval(() => {
const id = Date.now();
const data = `Hello World ${id}`;
const message =
`retry: ${refreshRate}\nid:${id}\ndata: ${data}\n\n`;
res.write(message);
}, refreshRate);
}
// Client side
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>SSE</title>
</head>
<body>
<pre id="log"></pre>
</body>
<script>
var eventSource = new EventSource('/events');
eventSource.onmessage = function(event) {
document.getElementById('log').innerHTML += event.data + '<br>';
};
</script>
</html>
`);
});
server.listen(port);
server.on('error', (err) => {
console.log(err);
process.exit(1);
});
server.on('listening', () => {
console.log(`Listening on port ${port}`);
});
If you're using express this is the easiest way https://www.npmjs.com/package/express-sse
on BE:
const SSE = require('express-sse');
const sse = new SSE();
...
app.get('/sse', sse.init);
...
sse.send('message', 'event-name');
on FE:
const EventSource = require('eventsource');
const es = new EventSource('http://localhost:3000/sse');
es.addEventListener('event-name', function (message) {
console.log('message:', message)
});
I found SSE implementation in node.js.
Github link: https://github.com/einaros/sse.js
NPM module:https://www.npmjs.com/package/sse
Will above link helps you ?
**client.js**
var eventSource = new EventSource("/route/events");
eventSource.addEventListner("ping", function(e){log(e.data)});
//if no events specified
eventSource.addEventListner("message", function(e){log(e.data)});
**server.js**
http.createServer((req, res)=>{
if(req.url.indexOf("/route/events")>=){
res.setHeader('Connection', 'keep-alive');
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Content-Type", "text/event-stream");
let event = "event: ping";
let id = `id: ${Date.now()}`;
let data = {
message:`hello #${new Date().toString()}`
}
data = "data: "+JSON.stringify(data);
res.end(`${event}\n${id}\n${data}\n\n`);
}
}).listen(PORT)
After looking at the other answers I finally got this working, but what I ended up having to do was a little different.
[package.json] Use express-sse:
The exact version of express-sse is very important. The latest tries to use res.flush(), but fails and crashes the http server.
"express-sse": "0.5.1",
[Terminal] Install express-sse:
npm install
[app.js] Use the router:
app.use(app.baseUri, require('./lib/server-sent-events').router);
[server-sent-events.js] Create sse library:
The call to pause() is the equivalent of flush(), which was removed from express. It ensures you'll keep getting messages as they are sent.
var express = require('express');
const SSE = require('express-sse');
const sse = new SSE();
var router = express.Router();
router.get('/sse', sse.init)
module.exports = {
send,
router
};
async function send(message) {
sse.send(message.toProperCase(), 'message');
await pause();
}
function pause() {
return new Promise((resolve, reject) => {
setImmediate(resolve)
})
}
[your-router.js] Use the sse library and call send:
var express = require('express');
var serverSentEvents = require('../lib/server-sent-events');
var router = express.Router();
router.get('/somepath', yourhandler);
module.exports = router;
async function yourhandler (req, res, next) {
await serverSentEvents.send('hello sse!'); // <<<<<
}
[your-client-side.js] Receive the sse updates:
I recommend you keep the event.data.replace(/"/g,'') because express-sse tacks on enclosing quotes and we don't want those.
const eventSource = new EventSource('http://yourserver/sse');
eventSource.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data.replace(/"/g,'') + '...';
};
You should be able to do such a thing using Socket.io. First, you will need to install it with npm install socket.io. From there, in your code you will want to have var io = require(socket.io);
You can see more in-depth examples given by Socket.IO
You could use something like this on the server:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port ' + port);
});
app.use(express.static(__dirname + '/public'));
io.on('connection', function (socket) {
socket.emit('EVENT_NAME', {data});
});
And something like this on the client:
<script src="socket_src_file_path_here"></script>
<script>
var socket = io('http://localhost');
socket.on('EVENT_NAME', function (data) {
console.log(data);
//Do whatever you want with the data on the client
});
</script>

Categories