Angular how to show live value of json object - node.js

In angular , I am trying to display one json object to client html. Using below route on server side.
const express = require('express');
const jsonRoute = express.Router();
jsonRoute .route('/json').get(function (req, res) {
var JsonObj = { rank: 73 } ;
res.end(JSON.stringify(JsonObj));
});
setInterval(function(){
JsonObj.rank = parseInt(Math.random()*100);
}, 1000); // this interval may be anything.from ms to minutes.
module.exports = jsonRoute ;
this works on http://localhost:4000/json and displays ,
{"rank":73}
But does not show the values changed in setInterval. And same route i am using in a angular service (using http).
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class getjsonService {
uri = "http://localhost:4000/json";
constructor(private http: HttpClient) { }
jsondata(){
return this.http.get(`${this.uri}`);
}
}
This value i am displaying in component html page. The problem is, it is not showing updated value of json. Please suggest how can i show live json value in angular. Please note, in realtime my json object going to be big in size , around 100 keys and value and i want to show live value for all key. And also change value interval may not be fix as one second. it may be in milliseconds as well.
Thanks

By default http will not persistent the connection. It's http protocol limitation not from angular.If you want to show the value in real time, you need to use web sockets.
There are lot of library out there will help with real time data connection. https://socket.io/ is very popular. check this out
Tutorial :https://alligator.io/angular/socket-io/

Your problem is a structural one with how RESTful architecture works. Your server only sends the new data to your angluar app when your app asks for it, not when your server detects a change. What you will need to do is either add a set timeout in your angular project that will call the server for the new data every few seconds.
setInterval(function(){ var JsonData = getJsonService.jsondata() }, 3000);
console.log(JsonData);
//This will refetch the data every 3 seconds you can lower this number to make it refresh more often
The other option is to rewrite your server to use web-sockets as Ravin pointed out.

In your node.js code, you are re-inializing the JsonObj variable every time the request is made. You should store the value as a global variable:
const express = require('express');
const jsonRoute = express.Router();
var JsonObj = { rank: 73 };
jsonRoute .route('/json').get(function (req, res) {
res.json(JsonObj);
});
setInterval(function(){
JsonObj.rank = parseInt(Math.random()*100);
}, 1000); // this interval may be anything.from ms to minutes.
module.exports = jsonRoute ;

Related

Custom Computed Etag for Express.js

I'm working on a simple local image server that provides images to a web application with some JSON. The web application has pagination that will do a get request "/images?page=X&limit&200" to an express.js server that returns the JSON files in a single array. I want to take advantage of the browser's internal caching such that if a user goes to a previous page the express.js returns an ETAG. I was wondering how this could be achieved with express.js? For this application, I really just want the computation of the ETAG to take in three parameters the page, the directory, and the limit (It doesn't need to consider the whole JSON body). Also this application is for local use only, so I want the server to do the heavy lifting since I figured it be faster than the browser. I did see https://www.npmjs.com/package/etag which seems promising, but I'm not sure how to use it with express.js
Here's a boilerplate of the express.js code I have below:
var express = require('express');
var app = express();
var fs = require('fs');
app.get('/', async (req, res) =>{
let files = [];
let directory = fs.readdirSync("mypath");
let page = parseInt(req.query.page);
let limit = parseInt(req.query.limit);
for (let i = 0; i < limit; ++i) {
files.push(new Promise((resolve) => {
fs.readFile(files[i + page * limit].name, (err, data) => {
// format the data so easy to use for UI
resolve(JSON.parse(data));
});
});
}
let results = await Promise.all(files);
// compute an etag here and attach it the results.
res.send(results);
});
app.listen(3000);
When your server sends an ETag to the client, it must also be prepared to check the ETag that the client sends back to the server in the If-None-Match header in a subsequent "conditional" request.
If it matches, the server shall respond with status 304; otherwise there is no benefit in using ETags.
var serverEtag = "<compute from page, directory and limit>";
var clientEtag = req.get("If-None-Match");
if (clientEtag === serverEtag) res.status(304).end();
else {
// Your code from above
res.set("ETag", serverEtag);
res.send(results);
}
The computation of the serverEtag could be based on the time of the last modification in the directory, so that it changes whenever any of the images in that directory changes. Importantly, this could be done without carrying out the fs.readFile statements from your code.

Using Firebase function as a proxy server

I built an app with Vuejs which is hosted on firebase, I recently added dynamic rendering with rendertron to improve SEO, I'm hosting the rendertron on Heroku. The rendertron client work well.
In order to send requests coming from bots like googlebot to rendertron and recieve a compiled HTML file, I used firebase function, it checks for the user agent, if it's a bot then it sends it to the rendertron link, if it's not, it fetches the app and resend result.
Here's the function code:
const functions = require('firebase-functions');
const express = require('express');
const fetch = require('node-fetch');
const url = require('url');
const app = express();
const appUrl = 'khbich.com';
const renderUrl = 'https://khbich-render.herokuapp.com/render';
function generateUrl(request){
return url.format({
protocol:request.protocol,
host:appUrl,
pathname:request.originalUrl
});
}
function detectBot(userAgent){
let bots = [
"googlebot",
"bingbot",
"facebookexternalhit",
"twitterbot",
"linkedinbot",
"facebot"
]
const agent = userAgent.toLowerCase()
for(let bot of bots){
if(agent.indexOf(bot)>-1){
console.log('bot-detected',bot,agent)
}
}
}
app.get('*', (req,res)=>{
let isBot = detectBot(req.headers['user-agent']);
if(isBot){
let botUrl= generateUrl(req);
fetch(`${renderUrl}/${botUrl}`)
.then(res => res.text())
.then(body=>{
res.set('Cache-Control','public','max-age=300','s-maxage=600')
res.set('Vary','User-Agent');
res.send(body.toString())
})
}
else{
fetch(`https://${appUrl}`)
.then(res=>res.text())
.then(body=>{
res.send(body.toString())
})
}
});
I used the function as an entry point for firebase hosting, so it's invoked whenever someone enters the app.
I checked on the firebase dashboard to see if it's working, and I noticed that it crashed for exceeding the number of requests per 100 second quota, I don't have much users when I checked, and the function invocations reached 370 calls in one minute.
I don't see why I had a large number of calls all at once, I'm thinking that maybe since I'm fetching the website if the user agent is not a bot, then the function is re-invoked causing an infinite loop of invocations, but I don't know if that's really why ?
If it's an infinite loop, how can I redirect users to their entered url without reinvoking the function ? will a redirect work ?

Is there a way to track an instance in Node without passing it around everywhere?

I have a singleton logger file. When a request comes into Express, I use middleware to set the request ID.
// Relevant parts of server.js
import express from 'express';
import requestIdMiddleware from './request-id-middleware';
const app = express();
app.use(requestIdMiddleware);
--
// Relevant parts of request-id-middleware.js
const uuid = require('uuid/v4');
const { setRequestId } = require('./logger');
module.exports = function(req, res, next) {
const id = uuid();
req.id = id;
// This sets a static variable on the plain logger object
setRequestId(id);
next();
};
--
// Relevant parts of logger.js
module.exports = {
request_id: null,
setRequestId: id => {
this.request_id = id;
},
log: message => {
// sends a log out using this.request_id, which is shared by all users of the server
}
}
Using the plain object now means everyone is sharing the same value. So despite each request calling setRequestId, it means if the first request takes longer than the second, it may use the second request's ID when referencing logger's value.
It seems I would need to make the logger a class instead of a plain object, instantiate it in my request middleware, and then pass the instance through to ensure unique request IDs across multiple calls from same request. Although unlikely, hoping to find a way around needing to pass a variable down into anything I want to log from.

nodejs why is variable persisting on page reloads?

I have the following express route:
const express = require('express');
const route = express.Router() ;
let a = 0;
route.get('/', (req,res)=> {
a++;
res.send(`hello api we are here! ${a}`)
})
module.exports = route;
When i log on to my localhost I get the message : hello api we are here! 1
then when i refresh: hello api we are here! 2
Every time i hit refresh the value of a increments. I always thought that when my browser connects to the server the entire server is reloaded and run from top. What am i missing?
Your variable a has a scope outside of the route.get. That a will increment and store for as long as your express server process is running.

handling Postbacks From other website to My website

Im using SuperRewards (SR) To make Coin transaction for users in my website,maybe you are familiar with SR.
Whenever a transaction happens SuperRewards sends a postback (Post Request) to my server containing information about the transaction and coins etc...
So my question is how to handle Postbacks or Post request ( i really dont know the diffrence ) from other website to my server USing Nodejs Express ?
Picture 1 App testing
picture 2 app Testing
Code
You would handle it like any other request coming to your Express app. Since it's a GET request, you would have a GET route defined.
According to section Fields and Formats, you get back quite a few query strings. Knowing that we can do the following:
app.get('/super-rewards', async (req, res) => {
// `new` is a reserved keyword, so we can't use `new` as a variable name.
const newCurrency = req.query['new']
const {
id,
uid,
oid,
total,
sig
} = req.query
})
Additionally, the documentation states that sig should match the MD5 hash of your secret key, if I'm understanding that correctly. So a full example would be something like:
const crypto = require('crypto')
const express = require('express')
const app = express()
app.get('/super-rewards', async (req, res) => {
// `new` is a reserved keyword, so we can't use `new` as a variable name.
const newCurrency = req.query['new']
const {
id,
uid,
oid,
total,
sig
} = req.query
const secretHash = crypto.createHash('md5').update(process.env.SECRET_KEY).digest('hex')
if (secretHash !== sig) {
throw new Error('Invalid transaction')
}
})
Aside, it is a GET request because the documentation clearly states that:
Postbacks are sent from our server to yours using a HTTP GET request (...)
I contacted the support team and they told me i must use a public domain not Local host that s why it wasnt working so the problem is solved and thank you for your time :)

Resources