NodeJS, Express and JSON API Response Time - node.js

I have create a simple express api to handle JSON data on my webapp.
Even if the app is on the same server, the response times are always on 100ms range, the actual data fetching is under 5ms;
Here is the data fetching zone :
export function getData(params) {
return new Promise((resolve, reject) => {
if (!params.take || params.take > 30 && isBrowser) {
params.take = 30;
}
console.time("API QUERY Execute");
{Data Fetching Goes here}
console.timeEnd("API QUERY Execute");
});
}
That method takes under 5 ms to complete from console.time.
Here is the express route config
app.route('/api/data').get((req, res) => {
getData(req.query)
.then((data) => {
res.json(data);
}).catch((err) => {
res.status(400);
res.send(err.message);
});
});
The actual Express App :
export default (parameters) => {
const app = Express();
const server = require('http').Server(app);
let io;
let redisCaching;
if (process.env.ENABLE_API === 'true') {
const Mongoose = require('mongoose');
const Redis = require('socket.io-redis');
Mongoose.connect(config.server.mongodb.url, config.server.mongodb.options);
Mongoose.connection.on('connected', () => {
console.log('==> Connected ', config.server.mongodb.url);
});
io = require('socket.io')(server);
io.sockets.on('connection', (socket) => {
console.log('==> Socket Connect', socket.handshake.headers.referer);
});
io.adapter(Redis({ host: 'localhost', port: 6379 }));
redisCaching = require('../../redis/redisCaching').redisCaching;
redisCaching.configure(6379, config.server.hostname);
}
if (process.env.CORS === 'true') {
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
}
app.route('/api/data').get((req, res) => {
getArticles(req.query)
.then((data) => {
res.json(data);
}).catch((err) => {
res.status(400);
res.send(err.message);
});
});
app.listen(process.env.PORT, () => {
console.log(`App listening on port ${process.env.PORT}`);
});
};
When using tools like pingdom, it showcases 100MS

Related

How to retrieve client ip address and find location using node js

I have tried using the following approach but when hosted the application . I'm getting the ip address that the application us hosted on.
Also I have used req.ip and req.socket.remoteAddress but it was returning the local host ip I.e ,::1
here is what I tried.
var express = require('express');
var request = require('request');
var app = express();
const IPData = require("ipdata").default;
require('dotenv').config();
const apiKey = process.env.API_KEY;
const ipdata = new IPData(apiKey);
app.get('/location', async (req, res) => {
try{
request.get('http://ipinfo.io/ip', (error, response, body) => {
if (!error && response.statusCode == 200) {
let clientIp = req.headers["x-forward-ip"] || body
console.log(body);
ipdata.lookup(clientIp)
.then((data) => {
console.log(data);
return res.json({
city: data.city,
region: data.region,
country: data.country_name,
postal: data.postal
});
})
.catch((error) => {
console.log(error);
res.status(500).send('Error looking up location');
});
}
});
}catch(error) {
console.log(error);
res.status(500).send('Error looking up location');
}
});
app.listen(8000, () => {
console.log('Server started on port 8000');
});
Try this:
const express = require("express");
const app = express();
const IpGeoLocation = require("ip-geolocation-api-javascript-sdk");
app.get("/", (req, res) => {
// Get client's IP address
const clientIp = req.connection.remoteAddress;
// Initialize IpGeoLocation with your API key
const apiKey = "YOUR_API_KEY";
const ipGeoLocation = new IpGeoLocation(apiKey);
// Get location information for the client's IP address
ipGeoLocation
.getGeoLocation(clientIp)
.then((location) => {
console.log(location);
res.send(location);
})
.catch((error) => {
console.error(error);
res.status(500).send(error);
});
});
app.listen(3000, () => {
console.log("Server listening on port 3000");
});
const ipGeoLocation = require("ip-geolocation-node");
const clientIp = req.connection.remoteAddress;
ipGeoLocation
.getGeoLocation(clientIp)
.then((location) => {
console.log(location);
})
.catch((error) => {
console.error(error);
});

NodeJS, Socket.io - The websocket getting disconnected immediately after getting connected

I have my backend in NodeJS and frontend in NextJS. As soon I try to connect with the server for a WebSocket connection, the server connects the socket and immediately disconnects it.
This is what I get on my server as soon as I reload my frontend page:
user connected ---- OKGG9r0qvvBs0EWeAAAB test#test.com socket disconnected--- OKGG9r0qvvBs0EWeAAAB test#test.com
This is my server code:
import express from "express";
import dotenv from "dotenv";
import http from "http";
import { Server, Socket } from "socket.io";
import userRoutes from "./routes/users";
import { DefaultEventsMap } from "socket.io/dist/typed-events";
dotenv.config();
const PORT = process.env.PORT || 5000;
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: process.env.CLIENT_URL,
},
});
app.use(express.json());
app.get("/ping", (req, res) => res.status(200).send("Pong"));
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Methods", "POST, GET");
res.header(
"Access-Control-Allow-Headers",
"Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
);
next();
});
interface SType extends Socket {
email?: string;
}
io.use((socket: SType, next) => {
const userEmail = socket.handshake.auth.email;
if (!userEmail) {
return next(new Error("Invalid email"));
}
console.log("userEmail-----", userEmail);
socket.email = userEmail;
next();
});
io.on("connection", (socket) => {
const users = [];
for (let [id, socket] of io.of("/").sockets) {
users.push({
userID: id,
email: (socket as any).email,
});
socket.emit("users", users);
}
socket.broadcast.emit("user connected", {
userID: socket.id,
email: (socket as any).email,
});
console.log("user connected ---- ", socket.id, (socket as any).email);
socket.on("disconnect", () => {
console.log("socket disconnected---", socket.id, (socket as any).email);
(socket as any).email = "";
});
});
app.use("/users", userRoutes);
server.listen(PORT, () => console.log(`server running on port ${PORT}`));
this is code on client side
useEffect(() => {
if (userState) {
socket.auth = { email: userState.email };
}
}, [userState]);
useEffect(() => {
socket.on("users", (users: any) => {
console.log("users", users);
setUsers(users);
});
socket.on("user connected", (user: any) => {
setUsers((previousState: any) => [...previousState, user]);
});
}, [socket]);
I tried the solutions from stack overflow as well as socket.io documentation, but nothing seems to work. Does anyone know what is happening here?

Can't connect to websocket server after pushing to vercel

When ever I run my server locally it works perfectly
But once I upload it to vercel I get errors like polling-xhr.js:202 GET https://giphy-chat-server.vercel.app/socket.io/?EIO=4&transport=polling&t=NQ03j3c&sid=H_PHDh9-4UKRVGTVAAAC 400
And WebSocket connection to 'wss://giphy-chat-server.vercel.app/socket.io/?EIO=4&transport=websocket&sid=k-Sex1ZKmrQQFoSKAAAA' failed: Error during WebSocket handshake: Unexpected response code: 400
I have tried so many solutions but none is working... I can't just figure out the problem. I would be glad if Its answered. Thank you
const express = require("express");
const app = express();
const http = require("http");
const path = require("path");
var server = http.createServer(app);
const io = require("socket.io")(server, {
cors: {
origin: "*",
credentials: true,
methods: ["GET", "POST"],
},
});
const { MONGODB_URI } = require("./config");
const port = process.env.PORT || 8000;
const Message = require("./message_model");
const mongoose = require("mongoose");
mongoose
.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
.then((result) => {
server.listen(port, () => {
console.log(`Listening on port ${port}...`);
});
})
.catch((err) => {
console.log(err);
});
app.use(express.static(path.join(__dirname, "..", "client", "build")));
const users = [];
io.on("connection", (socket) => {
users.push({ id: socket.id });
io.emit("users", { users: users });
Message.find()
.sort({ createdAt: -1 })
.limit(10)
.exec((err, messages) => {
if (err) return console.error(err);
socket.emit("init", messages);
});
socket.on("message", (msg) => {
const message = new Message({
content: msg.content,
name: msg.name,
});
message.save((err) => {
if (err) return console.error(err);
});
socket.broadcast.emit("push", msg);
});
socket.on("disconnect", (reason) => {
let index = -1;
for (let i = 0; i < users.length; i++) {
const user = users[i];
if (user.id === socket.id) {
index = i;
}
}
if (index !== -1) {
users.splice(index, 1);
}
io.emit("users", { users: users });
});
});
app.get("/", (req, res) => {
res.send("Giphy Chat Server is running successfully");
});
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
next();
});
I think this will be due to Vercel's serverless functions having a maximum execution timeout, so they can't maintain a websocket connection. In order to use Websockets with Vercel you'll need to use a third party service to handle your websocket connections for you. Something like Ably or Pusher, or PubNub.
I just wrote up a demo of next + ably if it would be helpful - https://github.com/ably-labs/NextJS-chat-app

Heroku: json data displayed instead of UI

My app works locally but once deployed to Heroku, every page works except the home page where the json data is displayed instead of the UI. On this page, I am listing the posts from the db so the posts in the db are being displayed as json data.
I tried prepending post routes with '/post' to stop api returning html on '/' route but now I'm getting this problem. Whatever I change, it just keeps switching between these two issues - either json data is displayed or index.html is returned instead of data.
How can I fix this?
Thanks!
The route for that specific page (this is the first route):
<Route path="/posts/" exact component={Home} />
server.js
// imports
...
require("dotenv").config();
// import routes
const authRoutes = require("./routes/auth");
const userRoutes = require("./routes/user");
const postRoutes = require("./routes/posts");
// app
const app = express();
// connect db
const url = process.env.MONGODB_URI
mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false,
});
mongoose.connection
.once("open", function () {
console.log("DB Connected!");
})
.on("error", function (error) {
console.log("Error is: ", error);
});
// middlewares
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
next();
});
//middleware
...
// routes middleware
// app.use(express.static(path.join(__dirname, './client/build')))
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
}
app.use(authRoutes);
app.use(userRoutes);
app.use('/post', postRoutes);
app.get("/*", function (req, res) {
res.sendFile(path.join(__dirname, "./client/build/index.html"));
});
const port = process.env.PORT || 80;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
ListPosts.js
// imports
...
import { API } from "../config";
class ListPosts extends React.Component {
state = {
title: "",
body: "",
date: "",
posts: [],
};
componentDidMount = () => {
this.getPosts();
};
getPosts = () => {
axios
.get(`${API}/post/`)
.then((response) => {
const posts = response.data;
this.setState({ posts });
})
.catch((error) => {
console.log(error);
});
};
displayPosts = (posts) => {
if (!posts.length) return null;
return posts.map((post, index) => (
...
));
};
render() {
return <div>{this.displayPosts(this.state.posts)}</div>;
}
}
export default ListPosts;
list route/controller
router.get("/", list);
exports.list = (req, res) => {
const sort = { title: 1 };
Post.find()
.sort(sort)
.then((posts) => res.json(posts))
.catch((err) => res.status(400).json("Error: " + err));
};

ERR_HTTP_HEADERS_SENT node js socket connection

I am building an API that uses socket connection to interact with a server backend built in C#. This is what I have so far
const request = require('request');
const express = require('express');
const app = express();
var server = require('http').createServer(app);
var cors = require("cors");
app.use(cors());
const net = require('net');
const client = new net.Socket();
const stringToJson=require('./stringToJson')
const port = process.env.PORT;
const host = process.env.HOST;
client.keepAlive=true
client.on('close', function() {
console.log('Connection closed');
});
app.get('/getScores',function (req,res) {
let dataSend=''
client.on('data', function (data) {
console.log('Server Says : ' + data);
if(data!='ANALYSIS-ERROR'){
dataSend=stringToJson.stringToJson(data)
}
else{
dataSend=stringToJson.stringToJson('0:0.0:0.0:0.0:0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0:0:0.0:0.0:0.0:0.0:0.0')
}
client.destroy()
return res.send(dataSend)
});
client.connect(port, host, function () {
client.write(`GENERAL-ANALYSIS|${req.query.id}|${req.query.website}|`)
return
});
return
})
app.get('/getPlace',function (req,res) {
console.log(req.query)
request(
{ url: `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${req.query.name}+in+${req.query.city}&key=${process.env.API_KEY}` },
(error, response, body) => {
if (error || response.statusCode !== 200) {
return res.status(500).json({ type: 'error', message: error.message });
}
return res.json(JSON.parse(body));
}
)
})
//TODO ADD 404 500 PAGES
app.use((req, res, next) => {
res.status(404).send("Sorry can't find that!");
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
server.listen(9000, () => {
console.log(`App running at http://localhost:9000`);
});
Basically it creates a connection with the server and listens for some data to be sent back. Then processes the string and sends it to the React frontend. The api calls are made by the frontend using axios
It works but if you refresh the page it throws this error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How do I fix this?
Try setting the headers as found in the documentation request.setHeader(name, value)
request.setHeader('Content-Type', 'application/json');

Resources