I send JSON data to route:
const data=[{name:this.name}]
//qs.stringify(payload)
axios
.post('/users',{name:this.name})
.then(
response => {
console.log(response.data);
}
)
.catch(
// error=>console.log(error)
)
And try get data:
router.post('/', function (req, res, next) {
var data = req.body; // here is your data
var obj=JSON.parse(data);
console.log(obj.toString());
res.toString("ok");
});
And I got error 500.
Why not get the data?
Your client side code is fine, except that the constant named data is entirely unused. On server-side however, req.body almost certainly contains a parsed JSON object (provided you have included a body paring middleware already). If you haven't included any body parsing middleware then req.body would be undefined.
Additionally, the toString() method in res doesn't send any response, it simply returns a string representation of the response.
You would need to make following changes to your code:
Include a body parsing middleware (eg. body-parser) to your express middleware chain, if one isn't already included.
Don't call JSON.parse(req.body). body-parser would already have done that. Calling it again will only throw exception, and return 500.
To convert an Object to JSON string, use JSON.stringify() method. obj.toString() will probably only return [object Object].
Send response using one of .send(), .json(), .end() methods on res. Since you need to send a string back, res.send("ok") seems most appropriate.
The changed code should appear something like this:
router.post('/', function (req, res, next) {
var data = req.body; // here is your data
console.log(JSON.stringify(data));
res.send("ok");
});
Related
I'm receiving a webhook from Shopify.
The endpoint is configured like this:
app.post('/webhook-receiver',async (req, res) => {
...function body here
})
When I log the request body like this I get undefined:
console.log(req.body) // returns undefined
But if I do this, I get the body:
import getRawBody from "raw-body"
const bodyBuffer = getRawBody(req);
console.log(JSON.parse(bodyBuffer.toString()); // returns the body expected
What is the reason ?
In a Firebase Function, I'm trying to accept a large string and store it.
exports.store = functions.https.onRequest(async (req, res) => {
const body : string = req.body;
await store(body);
return req.send(...);
});
I have found that using GZIP can improve performance and reduce file size by about 3-4x.
The problem is that if a client sends a GZip-encoded string with content encoding like so:
header("Content-Encoding", "gzip")
Then the call to req.body will 'automagically' decode the string to UTF-8. This both drastically reduces performance and requires me to again compress the string to efficiently store it in the server.
If I don't specify a content encoding then the endpoint will work as expected (i.e. it won't decompress the string and store it as-is, and run faster as a result). The problem is then I can't verify the user has sent a gzip-compressed string instead of a UTF-8 one, unless I implement some hacks to check for patterns in the string.
I am sure there is some simple solution, e.g.
functions.dontInflateTheRequestPleaseThanks();
exports.store = functions.https.onRequest(async (req, res) => {
if (req.headers["content-encoding"] !== "gzip") return res.status(415).send("gzip please");
const body : string = req.body;
await store(body);
return req.send(...);
});
The trick is to not pass Content-Encoding=gzip so express (the underlying framework) won't inflate (decompress) the request. Then to identify the request as a gzip, pass ContentType=application/gzip.
if (req.headers["content-encoding"] === "gzip") {
res.status(415).send("Don't specify gzip as the content-encoding. This trips up firebase.");
return;
}
if (req.headers["content-type"] !== "application/gzip") {
res.status(415).send("must be compressed using gzip");
return;
}
// Then body is guaranteed to not be fiddled with.
const body = req.body;
You have some middleware which fills req.body already and auto-decompresses it along the way. Instead, you can collect the body yourself.
Caution: The middleware that already fills req.body uses the same on("data")/on("end") technique as the code below, therefore you must make sure that this code is not executed together with the body-filling middleware.
To ensure this, pass an entire express app to functions.https.onRequest:
exports.store = functions.https.onRequest(express().use(async (req, res, next) => {
if (req.headers["content-encoding"] !== "gzip")
return res.status(415).send("gzip please");
var buffers = [];
req.on("data", function(data) {
buffers.push(data);
}).on("end", async function() {
await store(Buffer.concat(buffers));
res.send(...);
});
}));
I am submitting a form with an image. Using the below code.
router.post("/", upload.upload('image').single('categoryLogo'), categoryRules.categoryCreationRules(), validate, categoryController.createCategory);
It is working fine, but is some validation comes then still image is saving in disk.
so what I tried is :
router.post("/", categoryRules.categoryCreationRules(), validate,upload.upload('image').single('categoryLogo'), categoryController.createCategory);
But in this express validator getting blank body so it throws validation error very time.
What should I do for it, I search on google but I did not found any helpful info I am new in the node.
Rules code:
const categoryCreationRules = () => {
return [
check('name')
.isLength({ min: 1 })
.trim()
.withMessage("Category name is required."),
check('name').custom((name)=>{
return CategoryModel.findOne({name: name}).collation({locale:'en',strength: 2})
.then(category=>{
if(category){
return Promise.reject(category.name+" category already exsist.");
}
})
}),
check('name')
.isLength({max: 100})
.trim()
.withMessage("Category name should not exceed more then 100 characters."),
check('description')
.isLength({max: 255})
.trim()
.withMessage("Category description should not exceed more then 255 characters.")
];
}
In theory, running categoryCreationRules and validate middlewares before multer would be enough. Therefore, you would only need a verification in the request body and if it contains any errors, you just return a bad request response, not letting the request pass to the next middleware (in this case the multer).
A simple example what i'm talking about: (Just to let it clear, the below code won't work)
router.post("/", categoryRules.categoryCreationRules(), validate, upload.upload('image').single('categoryLogo'), categoryController.createCategory);
const validator = (req, res, next) => {
try {
validationResult(req).throw();
// Continue to next middleware, in this case, multer.
next();
} catch (errors) {
// return bad request
res.status(400).send(errors);
}
};
this won´t work because your req.body will be undefined, as you are sending the data as a multipart/form-data (generally used to upload files). And in this case, errors will always be true.
But with multer this will not happen - you will be able to access body fields like description and name and then do the validation code.
This occurs because multer, internally, parses the multipart/form-data request to body with a library called busboy, and with this you can access fields through req.body.
Because of that, i think the best approach here is call multer middleware before your validations middlewares:
router.post("/", upload.upload('image').single('categoryLogo'), categoryRules.categoryCreationRules(), validate, categoryController.createCategory);
And after that, if the validation has an error, you delete the file created from multer and return a bad request response, something like that:
const fs = require("fs");
const validator = (req, res, next) => {
try {
validationResult(req).throw();
// continue to next middleware
next();
} catch (errors) {
fs.unlink(req.file.path, (err) => {
if (err) {multipart/form-data
/* HANLDE ERROR */
}
console.log(`successfully deleted ${req.file.path}`);
});
// return bad request
res.status(400).send(errors);
}
};
You can get more info about this in the below links:
node-js-with-express-bodyparser-unable-to-obtain-form-data-from-post-request
req-body-undefined-multipart
html-multipart-form-data-error-in-req-body-using-node-express
To upload an image , you have set the enctype of form to multipart/form-data . But if you use multer later, you don't have the form data parsed, hence probaby giving undefined.
Please check multiparty , an npm module
https://www.npmjs.com/package/multiparty
It also parses other fields along with file uploads and validation might be easy to set.
Brothers and sisters, I am building an Express API Endpoint that needs to consume an external API, perform some changing of keys and values, and return to the result to the client. Here is what I have thus far:
const external_endpoint = <external_api_end_point>;
app.get('/', function (req, res, next) {
request({ url: external_endpoint}).pipe(res);
});
This returns the exact payload you would get from hitting the external_endpoint directly.
Isn't there something I can do to change res before it gets sent to the client? I tried a few things but nothings has worked. Any ideas or best practices associated with doing a transform on the incoming payload?
For the sake of simplicity. Lets say this is the payload obj.json:
{
"sad": {
"userid": 5,
"username": "jsmith",
"isAdmin": true
}
}
and I am wanting to change sad to happy.
I know outside of the request I could do something like this:
obj = JSON.parse(JSON.stringify(obj).split('"sad":').join('"happy":'));
but throwing obj in place of res will not work. I have tried assigning the value of this res and res.body but no dice.
Thanks for you help in advance!
If you're using request-promise, you can simply make a new response and send it, or modify the response you got back:
app.get('/', function (req, res, next) {
request({ url: external_endpoint, json: true})
.then(response => res.json({ happy: response.sad })))
.catch(next);
});
(of course, you need to handle errors appropriately)
If you want to process it as a stream (which makes sense if you have a massive amount of data), you can use the original request module, and use event-stream to create your pipe:
const es = require('event-stream');
const swapper = es.through(
function write(data) {
this.emit("data", data.replace("sad", "happy"));
},
function end() {
this.emit("end");
}
);
request({ url: external_endpoint})
.pipe(es.stringify())
.pipe(swapper)
.pipe(es.parse())
.pipe(res);
Here's a sandbox to test the stream processing: https://codesandbox.io/s/3wqx67pq6
Most of my handlers look as follows:
function(req, res) {
var data = ...;
res.render('my_view', data);
}
I know that If I want to return JSON I need to change res.render to res.json, as follows:
function(req, res) {
var data = ...;
res.json(data);
}
when debugging I often want to see the raw data (in JSON format that was computed by the handler). To do that, I (manually) go to the handler callback and change res.render('...', to res.json(.
I am wondering whether there is a way to tell express that if the URL meets a certain condition token (say, ends with .json, or, alternatively, has a ?format=json query param) then res.view will seamlessly delegate to res.json ?
If it is just for debugging purpose then you could make a middleware that would override render method to json.
I will not recommend to use this in production.
In your app.configure add this:
app.use(function(req, res, next) {
if (req.query.json !== undefined) {
res.render = function(name, data) {
res.json(data);
}
}
return next();
});
So what it does: if request has json in query, then it will override render method and will call json instead.
So test it with: http://example.com/test?json