nodejs with express streaming http response - node.js

I have the following test code:
const compression = require('compression');
const bodyParser = require('body-parser')
const cors = require('cors')
const { pool, connectionString } = require('./config')
const { handleError, ErrorHandler } = require('./error')
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(cors())
app.use(compression());
const getEvents = (request, response) => {
pool.connect((err, client, release) => {
if (err) {
throw new ErrorHandler(500, err.stack);
}
if(!request.query.FromTime){
throw new ErrorHandler(400, 'Required paramter FromTime is missing.');
}
if(!request.query.ToTime){
throw new ErrorHandler(400, 'Required paramter ToTime is missing.');
}
let fromtime = request.query.FromTime
let totime = request.query.ToTime
console.log("FromTime: ",fromtime," ToTime: ",totime);
let query = 'SELECT data FROM logs WHERE time BETWEEN '+fromtime+' AND '+totime+' ORDER BY time DESC';
console.log(query)
var stream = client.query(query, (error, results) => {
if (error) {
throw new ErrorHandler(500,error);
}
response.status(200).json(results.rows)
})
})
}
...
app
.route('/events')
// GET endpoint
.get(getEvents)
// POST endpoint
.post(addEvent)
app.use((err, req, res, next) => {
handleError(err, res);
});
// Start server
app.listen(process.env.PORT || 3002, () => {
console.log(`Server listening`)
})
I have been trying to get this to stream data instead but unsuccessfully. I did try pg-query-stream, with querystream but ended up with the following error, when i tried
var stream = client.query(new QueryStream(query));
stream.pipe(response);
_http_outgoing.js:607
throw new ERR_INVALID_ARG_TYPE('first argument',
^
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of
type string or Buffer. Received type object
at write_ (_http_outgoing.js:607:11)
at ServerResponse.write (_http_outgoing.js:579:10)
at ServerResponse.write (/usr/src/app/node_modules/compression/index.js:89:18)
at PgQueryStream.ondata (_stream_readable.js:705:22)
at PgQueryStream.emit (events.js:193:13)
at addChunk (_stream_readable.js:295:12)
at readableAddChunk (_stream_readable.js:276:11)
at PgQueryStream.Readable.push (_stream_readable.js:231:10)
at cursor.read (/usr/src/app/node_modules/pg-query-stream/index.js:55:14)
at Immediate.setImmediate (/usr/src/app/node_modules/pg-cursor/index.js:91:7)

response stream is not supported object mode by default.
Just try like in documents
const JSONStream = require('JSONStream')
stream.pipe(JSONStream.stringify()).pipe(response)

Related

Getting an error message n is not a function

I am writing a serverless netlify function when I hit /:uid endpoint, it shows me this error message n is not a function but when I hit / endpoint, it doesn't throw an error.
Please help me with this.
src/api.js file code
const express = require("express");
const cors = require("cors");
const fetch = require("node-fetch");
const helmet = require("helmet");
const serverless = require("serverless-http");
if (process.env.NODE_ENV !== "production") {
require("dotenv").config();
}
const app = express();
const router = express.Router();
app.use(cors());
app.use(helmet());
const fetchWithToken = (endpoint, method = "GET") => {
return fetch(`${process.env.API_BASE_URL}${endpoint}`, {
method,
headers: {
Authorization: `token ${process.env.TOKEN}`,
},
});
};
router.get("/", (req, res) => {
res.send("JDKJKFJ");
});
router.get("/:uid", async (req, res) => {
try {
const data = await fetchWithToken(`/${req.params.uid}`, "GET");
res.status(200).json(data);
} catch (error) {
console.log(error.message);
res.status(500).json({ error });
}
});
app.use("/.netlify/functions/api", router);
module.exports.handler = serverless(app);
error message
TypeError: n is not a function
at /Users/rishipurwar/codingspace-proxy-server/functions/api.js:159:3133
at /Users/rishipurwar/codingspace-proxy-server/functions/api.js:159:3232
at o.handle_request (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:120:783)
at o (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:113:879)
at d.dispatch (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:113:901)
at o.handle_request (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:120:783)
at /Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:2533
at f (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:3502)
at f (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:3696)
at Function.v.process_params (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:3839)
at g (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:2476)
at Function.v.handle (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:3340)
at p (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:238)
at o.handle_request (/Users/rishipurwar/codingspace-proxy-server/functions/api.js:120:783)
at /Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:2905
at /Users/rishipurwar/codingspace-proxy-server/functions/api.js:106:2927
Response with status 500 in 57 ms.
You need to add .json() to the returned value from fetch:
try {
let data = await fetchWithToken(`/${req.params.uid}`, "GET");
data = await data.json()
res.status(200).json(data);
} catch (error) {
console.log(error.message);
res.status(500).json({ error });
}

how to get a response in realtime in Nodejs

Hi I am trying to make a request and receive just the response in realtime using socketIO
and currently I am able to connect to the router but not getting any response as the error shows
Error: io is not defined.
If anyone can please help me to resolve this issue.
Below is the necessary code.
ChatPageProvider.dart
Future<void> addProduct(String message) async {
Map<String, String> headers = {
"Content-Type": "charset=utf-8",
"Content-type": "application/json"
};
const url = 'http://localhost:8080/message/check';
try {
var response = await http.post(url,
headers: headers,
body: json.encode({
"text": message,
}));
socketIO.init();
//Subscribe to an event to listen to
socketIO.subscribe('message', (jsonData) {
//Convert the JSON data received into a Map
Map<String, dynamic> data = json.decode(jsonData);
messages.add(data['message']);
notifyListeners();
});
socketIO.connect();
// final getMessage = Message(
// text: json.decode(response.body)['message'],
// );
print(response.statusCode);
notifyListeners();
} catch (error) {
throw error;
}
}
index.js
const express = require('express');
const app = express();
const notificationdetails = require('../nodePractice/router/notification');
const http = require('http').createServer(app);
const io = require('socket.io')(http);
bodyParser = require('body-parser');
var port = process.env.PORT || 8080;
app.use(bodyParser.json({limit: "50mb"}));
app.use(bodyParser.urlencoded({limit:"50mb",extended:true}));
io.on("connection",(userSocket) => {
console.log('Conntected to port')
io.emit('connected', 80);
})
var server = http.listen(port, ()=> {
console.log('listening on port' + port)
})
app.use(notificationdetails);
notification.js
const express = require('express');
const router = new express.Router()
router.post('/message/check',async(req,res) => {
console.log("Success"); // I am able to get till here but then the error occurs
io.emit("message", req.body)
try {
res.status(201).send();
io.emit("message", req.body)
}catch(e) {
res.status(401);
io.emit("message", req.body)
res.send(e);
}
})
module.exports = router
error
(node:78214) UnhandledPromiseRejectionWarning: ReferenceError: io is not defined
You can create a file like below, give it a name socket-io.js.
var io = require('socket.io')(9999);
module.exports = io;
Then import it first in your index.js like below snippet.
let io = require('./app/utilities/socket-io');
io.on('connection', function (socket) {
...
});
Last, you can import the same file in your notification.js file as well & try below code.
const express = require('express');
const router = new express.Router()
let io = require('./app/utilities/socket-io');
router.post('/message/check',async(req,res) => {
console.log("Success"); // I am able to get till here but then the error occurs
io.emit("message", req.body)
try {
res.status(201).send();
io.emit("message", req.body)
}catch(e) {
res.status(401);
io.emit("message", req.body)
res.send(e);
}
})
module.exports = router

"return next()" in node.js express throws "next is not defined" error

I'm working on a node.js application.
In my application the requests are going through a middleware which checks if the user is authenticated. In my middleware file though, I keep getting the "next is not defined" error back in my client. What might be the issue? I'm adding the App.js and the middleware file in here:
App.js:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const graphqlHttp = require('express-graphql');
const { sequelize } = require('./models');
const graphqlSchema = require('./graphql/schema');
const graphqlResolver = require('./graphql/resolvers');
const auth = require('./middleware/auth');
// return instance of the app
app = express();
// setting up the cors config
app.use(cors({
origin: '*'
}));
// tell the app to parse the body of the request
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
// tell the app to go through the middleware before proceeding to graphql
app.use(auth);
// setting the graphql route
app.use('/graphql', graphqlHttp({
schema: graphqlSchema,
rootValue: graphqlResolver,
graphiql: true,
formatError(err) {
if (!err.originalError) {
return err;
}
const data = err.originalError.data;
const message = err.message || 'An error occurred.';
const code = err.originalError.code || 500;
return { message: message, status: code, data: data };
}
})
);
app.use((error, req, res, next) => {
const status = error.statusCode || 500;
const message = error.message;
const data = error.data;
res.status(status).json({ message: message, data: data });
});
sequelize.sync({ force: true })
.then(() => {
app.listen(8080);
})
.catch(err => {
console.log(err);
});
the auth.js file (the middleware):
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const authHeader = req.get('Authorization');
if (!authHeader) {
req.isAuth = false;
return next();
}
const token = authHeader.split(' ')[1];
let decodedToken;
try {
decodedToken = jwt.verify(token, 'somesupersecretsecret');
} catch (err) {
req.isAuth = false;
return next();
}
if (!decodedToken) {
req.isAuth = false;
return next();
}
req.userId = decodedToken.userId;
req.isAuth = true;
next();
};

POST request not coming through (MERN)

I'm using the MERN stack to build an application for the first time.
In order to log HTTP requests I use "morgan".
I managed to send data to mongodb which seems to be working fine. The problem is that my post request is not coming through. It says "pending" for 4 minutes, then fails.
Here's what I think is the relevant part of my code:
"server.js":
const express = require("express");
const mongoose = require("mongoose");
const morgan = require("morgan");
const path = require("path");
const cors = require("cors");
const app = express();
const PORT = process.env.PORT || 8080;
const routes = require("./routes/api");
const MONGODB_URI =
"...";
mongoose.connect(MONGODB_URI || "mongodb://localhost/app", {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.connection.on("connected", () => {
console.log("Mongoose is connected.");
});
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
app.use(morgan("tiny"));
app.use("/api", routes);
app.listen(PORT, console.log(`Server is starting at ${PORT}`));
Then I've put my routes into another file "api.js":
const express = require("express");
const router = express.Router();
const Lane = require("../models/lanes");
router.get("/", (req, res) => {
Lane.find({})
.then(data => {
res.json(data);
console.log("Get request successful!");
})
.catch(error => {
console.log("Error: ", error);
});
});
router.post("/save", (req, res) => {
const data = req.body;
const newLane = new Lane();
newLane.collection.insertMany(data, err => {
if (err) {
console.log(err);
} else {
console.log("Multiple docs inserted");
}
});
});
module.exports = router;
I'm using axios to send the request. This happens after submitting a form within my application.
reducer function:
const reducer = (state, action) => {
switch (action.type) {
case "add":
axios({
url: "http://localhost:8080/api/save",
method: "POST",
data: [...state, { id: uuid(), title: action.title, tasks: [] }]
})
.then(() => {
console.log("Data has been sent to the server");
})
.catch(() => {
console.log("Internal server error");
});
return [...state, { id: uuid(), title: action.title, tasks: [] }];
The reducer is being used by my context provider component, which looks like this:
export function LanesProvider(props) {
const [lanes, dispatch] = useReducer(reducer, defaultLanes);
return (
<LanesContext.Provider value={lanes}>
<DispatchContext.Provider value={dispatch}>
{props.children}
</DispatchContext.Provider>
</LanesContext.Provider>
);
}
The "add" method inside my reducer is being called when submitting a form inside another component.
Please let me know if I can add anything to my question that would help.
Thank you in advance!
you are not sending any response back to client. Try to modify post method like
router.post("/save", (req, res) => {
const data = req.body;
const newLane = new Lane();
newLane.collection.insertMany(data, err => {
if (err) {
console.log(err);
res.send(err)
} else {
console.log("Multiple docs inserted");
res.send("Multiple docs inserted")
}
});
});

Node.js + Express - How to log the request body and response body

I have a small api I have built using Node.js and express.
I am trying to create a logger and I need log the request body AND response body.
app.use((req, res) => {
console.log(req);
res.on("finish", () => {
console.log(res);
});
});
"express": "^4.16.3",
However, i am not able to find the body in the req or res object. Please tell me how i can get them. thanks.
For res.body try the following snippet:
const endMiddleware = (req, res, next) => {
const defaultWrite = res.write;
const defaultEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(new Buffer(restArgs[0]));
defaultWrite.apply(res, restArgs);
};
res.end = (...restArgs) => {
if (restArgs[0]) {
chunks.push(new Buffer(restArgs[0]));
}
const body = Buffer.concat(chunks).toString('utf8');
console.log(body);
defaultEnd.apply(res, restArgs);
};
next();
};
app.use(endMiddleware)
// test
// HTTP GET /
res.status(200).send({ isAlive: true });
You need body-parser that will create body object for you in your request. To do that
npm install body-parser
var bodyParser = require('body-parser')//add this
app.use(bodyParser())//add this before any route or before using req.body
app.use((req, res) => {
console.log(req.body); // this is what you want
res.on("finish", () => {
console.log(res);
});
});
Ran into this problem but didn't like the solutions. An easy way is to simply wrap the original res.send or res.json with your logger.
Put this as middleware before your routes.
app.use(function responseLogger(req, res, next) {
const originalSendFunc = res.send.bind(res);
res.send = function(body) {
console.log(body); // do whatever here
return originalSendFunc(body);
};
next();
});
https://github.com/expressjs/express/blob/master/lib/response.js
res.send has signature of function(body) { return this; }
Here is a working example using the built in PassThrough stream. Remember to use the express.json() built in middleware to enable request body parsing.
After that, you need to intercept all writes to the response stream. Writes will happen on calling write or end, so replace those functions and capture the arguments in a separate stream.
Use res.on('finish', ...) to gather all the written data into a Buffer using Buffer.concat and print it.
const express = require('express');
const { PassThrough } = require('stream')
const app = express();
app.use(express.json());
app.use((req, res, next) => {
const defaultWrite = res.write.bind(res);
const defaultEnd = res.end.bind(res);
const ps = new PassThrough();
const chunks = [];
ps.on('data', data => chunks.push(data));
res.write = (...args) => {
ps.write(...args);
defaultWrite(...args);
}
res.end = (...args) => {
ps.end(...args);
defaultEnd(...args);
}
res.on('finish', () => {
console.log("req.body", req.body);
console.log("res.body", Buffer.concat(chunks).toString());
})
next();
})
app.use('/', (req, res) => {
res.send("Hello");
});
app.listen(3000);
install npm install body-parser
and use this snippet,
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// create application/json parser
var jsonParser = bodyParser.json()
to get json response
app.use(jsonParser, function (req, res) {
console.log(req.body); // or console.log(res.body);
})
There is ready made module https://www.npmjs.com/package/morgan-body
const express = require('express')
const morganBody = require("morgan-body")
const bodyParser = require("body-parser")
const app = express()
const port = 8888
// must parse body before morganBody as body will be logged
app.use(bodyParser.json());
// hook morganBody to express app
morganBody(app, {logAllReqHeader:true, maxBodyLength:5000});
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Hi was looking for same as complete log of request and response as middleware in express js. Found the solution as well w
/*Added by vikram parihar for log */
const moment = require('moment');
const rfs = require("rotating-file-stream");
const geoip = require('geoip-lite');
const { PassThrough } = require('stream')
let path = require('path');
const accessLogStream = rfs.createStream('access.log', {
interval: '1M', // rotate daily
compress: true,
path: path.join(__dirname, '../../log')
});
module.exports = function (req, res, next) {
try {
let geo = geoip.lookup(req.ip);
let country = geo ? geo.country : "Unknown";
let region = geo ? geo.region : "Unknown";
let log = {
"time": moment().format('YYYY/MM/DD HH:mm:ss'),
"host": req.hostname,
"ip": req.ip,
"originalUrl": req.originalUrl,
"geo": {
"browser": req.headers["user-agent"],
"Language": req.headers["accept-language"],
"Country": country,
"Region": region,
},
"method": req.method,
"path": req.path,
"url": req.url,
"body": req.body,
"params": req.params,
"query": req.query,
"response": {
"body": res.body
}
};
const defaultWrite = res.write.bind(res);
const defaultEnd = res.end.bind(res);
const ps = new PassThrough();
const chunks = [];
ps.on('data', data => chunks.push(data));
res.write = (...args) => {
ps.write(...args);
defaultWrite(...args);
}
res.end = (...args) => {
ps.end(...args);
defaultEnd(...args);
}
res.on('finish', () => {
log.response.body = Buffer.concat(chunks).toString()
accessLogStream.write(JSON.stringify(log) + "\n");
})
} catch (error) {
console.log(error)
next(error)
}
next();
}

Resources