Parsing JSON in Express without BodyParser - json

I'm trying to write a simple express server that takes incoming JSON (POST), parses the JSON and assigns to the request body. The catch is I cannot use bodyparser. Below is my server with a simple middleware function being passed to app.use
Problem: whenever I send dummy POST requests to my server with superagent (npm package that lets you send JSON via terminal) my server times out. I wrote an HTTP server in a similar fashion using req.on('data')...so I'm stumped. Any advice?
const express = require('express');
const app = express();
function jsonParser(req, res, next) {
res.writeHead(200, {'Content-Type:':'application/json'});
req.on('data', (data, err) => {
if (err) res.status(404).send({error: "invalid json"});
req.body = JSON.parse(data);
});
next();
};
app.use(jsonParser);
app.post('/', (req, res) => {
console.log('post request logging message...');
});
app.listen(3000, () => console.log('Server running on port 3000'));

I think the problem like to get rawBody in express.
Just like this:
app.use(function(req, res, next){
var data = "";
req.on('data', function(chunk){ data += chunk})
req.on('end', function(){
req.rawBody = data;
req.jsonBody = JSON.parse(data);
next();
})
})
And you need catch the error when parse the string to json and need to judge the Content-type of the Req.
Good luck.

another way that worked with me by collecting all chunks into an array and parsing the concatenated chunks.
app.use("/", (req, res, next)=>{
const body = [];
req.on("data", (chunk) => {
console.log(chunk);
body.push(chunk);
});
req.on("end", () => {
const parsedBody = Buffer.concat(body).toString();
const message = parsedBody.split('=')[1];
console.log(parsedBody);
console.log(message);
});
console.log(body);
});

To get access to req.body this worked for me:
app.use(express.json({extended: false}));

In Express v4.16.0 onwards:
app.use(express.json())

Related

Create Web server using Node js model MVC

I'm trying to create a web server, and I'm using to MVC model so I tried to use routes inside so I don't know how can I do this. in the console log thats return all data otherwise in postman I test it it doesn't works. here is my code.
AirModel.js :
AirMonitoring.getAllData = (result) =>{
db.query('SELECT * FROM AirMonitoring', (err, res)=>{
if(err){
console.log('Error while fetching airMonitoring', err);
result(null,err);
}else{
console.log('AirMonitoring fetched successfully');
result(null,res);
}
})
}
airController.js :
exports.getAllData = (req, res)=> {
AirModel.getAllData((err, airMonitoring) =>{
if(err)
res.send(err);
console.log('data', airMonitoring);
res.send(airMonitoring)
})
}
index.js :
const server = http.createServer(function(req, res) {
console.log("http was created!");
if(req.url == '/airMonitoring'){
res.writeHead(200, { 'Content-Type': 'application/json' });
// get latest record of airMonitoring
router.get('/airMonitoring', airController.getAllData);
res.end();
}
});
It's not very clear what router is but I'm assuming it's an express router, and that's not how routing works. Currently you are (re?)defining the route on each request. The routing page is a good place to start, but basically you need to define the routes once.
var express = require('express')
var app = express()
app.get('/airMonitoring', airController.getAllData);
app.listen(PORT, () => {
console.log(`Example app listening at http://localhost:${PORT}`)
})
And also in your AirModel.js you have an error as far as I can tell, when handling the database error you should provide it as first argument, not second:
result(null,err); /* has to be result(err, null) */

req.body is empty prototype in onRequest firebase cloud functions (With multer)

In my cloud function:
const app = express();
app.use(multer().array());
app.post("/", (req, res) => {
console.log("hit", req.body.from);
console.log("hit", req.body.from);
return res.sendStatus(200);
});
const emailInboundWebhook = functions.https.onRequest(app);
module.exports = {
emailInboundWebhook
}
I get this in logs:
i functions: Beginning execution of "emailInboundWebhook"
> hit undefined
> hit undefined
i functions: Finished "emailInboundWebhook" in ~1s
But when the same endpoint served as an express app(outside cloud functions):
const express = require("express");
const app = express();
const multer = require('multer');
app.get("/", async (req, res) => {
res.status(200).json({foo: "Bar"});
})
app.use(multer().array());
app.post("/webhook", async (req, res) => {
console.log("hit",req.body.to);
console.log("hit",req.body.from);
res.sendStatus(200);
});
app.listen(80, () => {
console.log("App listening on 80");
})
Gives this:
hit a#some-email-inbound.some.url
hit Rahul Priyadarsi <myemailid#gmail.com>
The two results are for same email sent and these functions are fired as sendgrid webhooks which send multipart/form-data POST requests that contain details of the email sent to a#some-email-inbound.some.url from myemailid#gmail.com
I have no idea as to why the two results are different(I am testing them via ngrok and since the console log lines run, clearly the function is hit).
I had the same problem.
Take a look in this issue: https://github.com/expressjs/multer/issues/572
Switch from Multer to Busboy, is also a good option.
One thing: In this situation use https.Request (from cloud-functions) instead of Request from express.

How to dynamically fetch JSON based on param in express

I'm new to node and express but trying to dynamically fetch JSON based on the user's language settings. I need to figure out how to serve up the params:
I was thinking to try and set the "lang" param to its own variable and return that, but I am reading on SO that this is not best practice: Use variable's value as variable in javascript
var express = require("express");
var english = require('./Data/english.json');
var spanish = require('./Data/spanish.json');
var app = express();
app.use(function (req, res, next) {
console.log('inside of app.use');
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-
With, Content-Type, Accept");
next();
});
app.get("/:lang", function (req, res, next) {
const lang = req.params.lang;
console.log(lang)
res.send(lang);
});
app.listen(5000, () => console.log('Listening on port 5000!'))
I would like to be able to dynamically return the appropriate json file ! Any thoughts much appreciated.
TL;DR
Use the fs module to read you JSON files
Call JSON.parse() to parse the raw JSON
Choose the file according to var lang = req.params.lang using some kind of logic (for example, 'spanish' -> './data/spanish.json')
Code
const fs = require('fs');
// Supported languages
const supportedLanguages = ['english', 'spanish'];
app.get("/:lang", function (req, res, next) {
const lang = req.params.lang;
if (supportedLanguages.indexOf(lang) === -1) {
res.status(400).send('Language not supported');
} else {
fs.readFile(`./Data/${lang}.json`, (err, data) => {
// If error send a 500 status
if (err) res.status(500).send(err);
// Else parse the JSON file and send it
else res.send(JSON.parse(data));
});
}
});
It's simple to return json data with express.
Just use res.json({key: value , key2: value2}) instead of res.send
In your case, you can
const language = req.params.lang;
res.json({lang: lang})
you will receive a JSON object instead of text

node js res Cannot GET /

I launch the Ubuntu on EC2 and running the app on port 80 using nginx. I am trying to exact the data using RESTful get from json "http://data.fixer.io/api/latest?access_key=xxx" and render a table. However, Cannot GET / pops out.
The following code is workable:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('HEY!')
})
app.listen(3000, () => console.log('Server running on port 3000'))
But my code doesnt work.
var request = require("request");
var EventEmitter = require("events").EventEmitter;
var body = new EventEmitter();
request("http://data.fixer.io/api/latest?access_key=xxx", function(error, response, data) {
body.data = data;
body.emit('update');
});
body.on('update', function () {
console.log(body.data);
});

node and express send json formatted

I'm trying to send formatted json with express.
Here is my code:
var app = express();
app.get('/', function (req, res) {
users.find({}).toArray(function(err, results){
// I have try both
res.send(JSON.stringify(results, null, 4));
// OR
res.json(results);
});
});
I get the json in my browser but it's a string.
How can I send it so it's readable in the browser?
try to set the "secret" property json spaces on the Node app.
app.set('json spaces', 2)
This statement above will produce indentation on json content.
You're going to have to set the Content-Type to application/json like this
app.get('/', function (req, res) {
users.find({}).toArray(function(err, results){
res.header("Content-Type",'application/json');
res.send(JSON.stringify(results, null, 4));
});
});
Use type('json') to set Content-Type and JSON.stringify() for formatting:
var app = express();
app.get('/', (req, res) => {
users.find({}).toArray((err, results) => {
res.type('json').send(JSON.stringify(results, null, 2) + '\n');
});
});
Sending JSON output as formatted from the server could be undesirable considering resource usage and performance of the server. Especially in production environments.
Instead, you can find a few ways to format the JSON output at client-side.
If you are using Chrome, you can use an extension among JSON Formatter, JSON Viewer, JSONView or others from Chrome web store.
Firefox provides built-in JSON viewer since Firefox 44.
When using curl or wget in a command line or a shell script, you can pipe the result in JSON into jq.
$ curl http://www.warehouse.com/products | jq .
This should solve your problem
var app = express();
app.set('json spaces', 4)
app.get('/', function (req, res) {
users.find({}).toArray(function(err, results){
res.json(JSON.parse(results));
});
});
For convenience, you can override res.json in a custom middleware that runs before your routes.
To auto-format all JSON responses:
app.use('*', (req, res, next) => {
res.json = (data) => res.type('json').send(JSON.stringify(data, null, 4))
next()
})
app.get('/route', (req, res) => res.json({ formatted: true })
To allow custom formatting based on individual routes or other logic:
app.use('*', (req, res, next) => {
res.json = (...args) => res.type('json').send(JSON.stringify(...args))
next()
})
app.get('/tabs', (req, res) => res.json({ formatted: 'tabs' }, null, '\t')
app.get('/spaces', (req, res) => res.json({ formatted: 'spaces' }, null, 4)
app.get('/minified', (req, res) => res.json({ formatted: false })
Maybe you need to JSON.parse(resp)