How to read BSON data in Express.js with body parser - node.js

I have a Node.js API using Express.js with body parser which receives a BSON binary file from a python client.
Python client code:
data = bson.BSON.encode({
"some_meta_data": 12,
"binary_data": binary_data
})
headers = {'content-type': 'application/octet-stream'}
response = requests.put(endpoint_url, headers=headers, data=data)
Now I have an endpoint in my Node.js API where I want to deserialize the BSON data as explained in the documentation: https://www.npmjs.com/package/bson. What I am struggling with is how to get the binary BSON file from the request.
Here is the API endpoint:
exports.updateBinary = function(req, res){
// How to get the binary data which bson deserializes from the req?
let bson = new BSON();
let data = bson.deserialize(???);
...
}

You'll want to use https://www.npmjs.com/package/raw-body to grab the raw contents of the body.
And then pass the Buffer object to bson.deserialize(..). Quick dirty example below:
const getRawBody = require("raw-body");
app.use(async (req, res, next) => {
if (req.headers["content-type"] === "application/octet-stream") {
req.body = await getRawBody(req)
}
next()
})
Then just simply do:
exports.updateBinary = (req, res) => {
const data = new BSON().deserialize(req.body)
}

You could as well use the body-parser package:
const bodyParser = require('body-parser')
app.use(bodyParser.raw({type: 'application/octet-stream', limit : '100kb'}))
app.use((req, res, next) => {
if (Buffer.isBuffer(req.body)) {
req.body = JSON.parse(req.body)
}
})

Related

How to make nodejs server act like a proxy and get img from cloudinary then send it to browser

for storage space issues i cannot save images in server so i had to store it in cloudinary
and for seo purposes I had to serve it from my domain not cloudinary's
so i thought to get img files from cloudinary and send it directly to browser (to be served from my domain name )
what i am missing is converting the img file i got from cloudinary api into the right form so i can send it using response object in nodejs
here is the code
app.get('/uploads/img/:imgName', (req, res) => {
axios.get('https://res.cloudinary.com/dkhccaa25/image/upload/blog_img/${req.params.imgName}')
.then(response => {
console.log(response);
/* how to convert response into the right format so it can be sent */
//
//
//
})
.then (response => {
/*converted response */
res.sendFile(response)
})
.catch(error => {
console.log(error);
});
how I can be able to send the file from node server to browser so it can be displayed using
<img src="img url...">
You do not have to use res.sendFile, this will require saving it to the filesystem. Basically - accept the response and pass it directly with the correct content-type header send by the upstream response to the client.
Minimal example:
const express = require('express');
const axios = require('axios');
const app = express();
app.get('/', (req, res) => {
axios.get('https://static.pexels.com/photos/45201/kitty-cat-kitten-pet-45201.jpeg').then((axiosResp) => {
res.header('content-type', axiosResp.headers['content-type']).send(axiosResp.data);
});
});
app.listen(3000);
finally the problem solved by editing on #madflow answer (thanks for him )
const express = require('express');
const axios = require('axios');
const app = express();
app.get('/', (req, res) => {
axios.get('https://static.pexels.com/photos/45201/kitty-cat-kitten-pet-45201.jpeg', {responseType: 'stream'})
.then((axiosResp) => {
res.set({
'Content-Type': axiosResp.headers['content-type']
})
axiosResp.data.pipe(res)
});
});
app.listen(3000);

Is there any way to accept binary data type like pdf in serverless?

I am facing the issue like the following:
When uploading a pdf file in vue.js to serverless node.js application, file content is broken.
Because the serverless parses binary data type incorrectly, it happens the issue.
How can I accept binary data type like pdf correctly or other method to solve the issue?
// Vue.js
let formData = new FormData();
formData.append('file', fileObj);
axios.post(API_ENDPOINT + '/upload', formData).then(resp => {
console.log(resp);
})
// Serverless Express
const express = require('express');
const app = express();
const fileUpload = require('express-fileupload');
app.use(fileUpload());
app.post('/upload', (req, res) => {
console.log(req.files.file) // Uploaded tmp file - It has broken content
});
Currently I am using multiparty. I will provide the middleware in the following snippet of code
const { Form } = require('multiparty')
function formDataParser(req, res, next) {
if (!req.is('multipart/form-data')) {
next();
return;
}
const form = new Form();
form.parse(req, (err, fields, files) => {
if (err) {
res.status(400).json({
message: 'Could not parse multipart form.'
});
return;
}
const fieldsKeys = Object.keys(fields);
for (const fieldKey of fieldsKeys) {
fields[fieldKey] = fields[fieldKey][0];
}
req.form = {
fields,
files
}
next();
});
}
module.exports = formDataParser;
I suggest not to attach this middleware as a global one but instead use it only on specific routes that need it. With the provided solution you can access form fields in the following way:
req.form.fields.somefield

Express JS proxy to call web api

I have the following code. And a web api which returns string array,
const express = require('express');
const proxy = require('express-http-proxy');
var app = express();
app.use('/proxy', proxy('http://localhost:56660/api/values'));
app.listen(3000);
When I tried to do localhost:3000/proxy I do not get a response,
But when I use app.use('/proxy', proxy('www.google.com')); , it redirects to google web site.
Please suggest me a best approach/solution:
I want to create a proxy server which gets url from browser (Application), modify the url, call the new url and send the response back to browser(Application).
You can get the URL to be proxied as a query parameter, modify it and then pass that URL to proxy, like this (use instead of app.use('/proxy', proxy('http://localhost:56660/api/values'));):
app.get('/proxy', (req, res, next) => {
const modifiedURL = modifyURL(req.query.url)
return proxy(modifiedURL)(req, res, next)
})
You can call you server with an URL like this (GET method):
https://my.server.com/proxy?url=https://urltobeproxied.com
UPDATE:
I think this would work according to your needs:
app.use('/proxy', (req, res, next) => {
const requestedUrl = `${req.protocol}://${req.get('Host')}${req.url}`
const modifiedURL = modifyURL(requestedUrl)
proxy(modifiedURL)(req, res, next)
})
UPDATE2:
app.use('/proxy', proxy('http://localhost:56660/api/values', {
proxyReqPathResolver: function(req) {
const requestedUrl = `${req.protocol}://${req.get('Host')}${req.url}`
const modifiedURL = modifyURL(requestedUrl)
return require('url').parse(modifiedURL).path;
}
}))
UPDATE3:
An example of proxy modifying the response (extracted from the package docs);
app.use('/proxy', proxy('http://localhost:56660/api/values', {
userResDecorator: function(proxyRes, proxyResData, userReq, userRes) {
data = JSON.parse(proxyResData.toString('utf8'));
data.newProperty = 'exciting data';
return JSON.stringify(data);
}
}))

sails.js Getting a POST payload with text/plain content type

I'm developing a sails.js (node.js framework based on express) aplication, which is going great but ]I can't solve this detail...
I need to send POST requests cross domain from internet explorer 8 and 9. For that I'm forced to use xDomainRequest object, wich doesn't allow to set a Content type header.
So, when the request gets to the server the content type is "text/plain", which doesn't fire the bodyParser express middleware, so my req.body is an empty object and I can't see the payload I'm sending from the client.
For this I've tried two things with no luck:
First I wanted to set a header to the request in my first middleware, which is of course not available:
req.set("Content-type", "Apli.....
Then, I created a middleware that listens to req.on('data'), like this:
var data = "";
req.on('data', function(chunk){
data += chunk;
});
req.on('end', function(){
req.rawBody = data;
next();
});
But the data event never fires!
Does anyone know how can I access my raw payload, so I can parse it myself.
Thanks!
with newest version of Sails, using express is deprecated.
I needed to use a specific parser to get raw data from Stripe API.
Here is my code, maybe it will help somebody :
bodyParser: function(req, res, next) {
var skipper = require('skipper')();
var rawParser = require("body-parser").raw({type: "*/*"});
// Create and return the middleware function
return function(req, res, next) {
sails.log.debug(req.headers);
if (req.headers && req.headers['stripe-signature']) {
sails.log.info('request using raw parser middleware');
return rawParser(req, res, next);
}
// Otherwise use Skipper to parse the body
sails.log.info('request using skipper middleware');
return skipper(req, res, next);
};
},
I think in this case you're going to have to implement your own body parser, which you can set as sails.config.express.bodyParser or create a config/express.js file like:
var express = require('express');
module.exports.express = {
bodyParser: function(options) {
// Get default body parser from Express
var defaultBodyParser = express.bodyParser(options);
// Get function for consumung raw body, yum.
var getBody = require('raw-body');
return function (req, res, next) {
// If there's no content type, or it's text/plain, parse text
if (!req.headers['content-type'] ||
req.headers['content-type'].match('text/plain')) {
// flag as parsed
req._body = true;
// parse
getBody(req, {
limit: 100000, // something reasonable here
expected: req.headers['content-length']
}, function (err, buf) {
if (err) return next(err);
// Make string from buffer
buf = buf.toString('utf8').trim();
// Set body
req.body = buf.length ? {content: buf} : {}
// Continue
next();
});
}
// Otherwise try the default parsers
else return defaultBodyParser(req, res, next);
};
}
You'll have to npm install express and npm install raw-body. Note that this example uses the default Express body parser as a fallback, not the default Sails body parser which isn't exposed anywhere (and is mostly the same as Express anyway, sans the JSON retry).
maxime's answer is mostly correct. minor modification needed as follows:
bodyParser: function(req, res, next) {
var skipper = require('skipper')();
var rawParser = require("body-parser").raw({type: "*/*"});
// Create and return the middleware function
sails.log.debug(req.headers);
if (req.headers && req.headers['stripe-signature']) {
sails.log.info('request using raw parser middleware');
return rawParser(req, res, next);
}
// Otherwise use Skipper to parse the body
sails.log.info('request using skipper middleware');
return skipper(req, res, next);
},

nodejs request module parse body

I have the following code:
var express = require('express');
var app = express.createServer();
var request = require('request');
app.use(myMiddleware);
app.listen(5010);
var payload = { id: 1 };
request({
method: 'POST',
body:JSON.stringify(payload),
url: 'http://localhost:5000'
}, function(err, res, body) {
console.info("Request Done");
})
In my middleware code I want to parse the body and extract the request id, yet for some reason the following code doesn't work (payload is undefined):
var myMiddleware= function (req, res, next){
var payload = req.body;
if (payload.id === 1) console.info("first request!!!!!");
next();
}
When I try to print "payload" all I get is [object Object].
Could you please tell me how to extract the id, and how to print the attributes of the payload object?
Thanks,
Li
Solved by adding:
app.use(express.bodyParser());
and by adding the following to the request code:
json: true
After adding the json=true attribute I also removed JSON.stringify(...) from the body of the request (now I don't need to stringify the body since it expects a json object)
Thanks.

Resources