My custom express json middleware is not working properly - node.js

i have tried implementing my own middleware which is similar to app.use(express.json())
the code is here
const rahul_express={
json(){
return (req,res,next)=>{
let arr=[]
req.on('data',(chunk)=>{
arr.push(chunk)
})
req.on('end',(fin)=>{
const parserbody=new Buffer.concat(arr).toString()
req.body=JSON.parse(parserbody)
console.log(req.body)
})
next()
}
}
}
app.use(rahul_express.json())
i have tried parsing the JSON and adding it the req but still in other middleware i can't access the req.body data,i don't know why,any help will be appreciated!

Events are called "asynchronously," meaning that the code doesn't wait until the event is emitted. This means that next() is ran before the events are finished.
The correct approach to this problem is to use next() inside of the end event's callback, like so:
req.on('end', (fin) => {
const parserbody = new Buffer.concat(arr).toString();
req.body = JSON.parse(parserbody);
console.log(req.body);
next();
})

Related

Can I make a fetch request from an express request handler or middleware?

Let's say I have an express api with an /api/load-post endpoint. That is handled by the loadPostHandler: RequestHandler
index.ts
const app = express();
app.get("/api/load-post", loadPostHandler);
loadPostHandler.ts
Can I make a fetch request from that handler?
import fetch from "cross-fetch";
export const loadPostHandler: RequestHandler = async (req, res) => {
// HANDLE BLOGPOST LOAD
res.json({ blogPost: blogPostData }) // RES JSON THE BLOGPOST DATA
await fetch("/api/updateViewcount?id=POST_ID"); // MAKE A FETCH REQUEST
};
Is this something people usually do? Or is this an anti-pattern? Not sure if this would even work.
Short answer
Yes, you can make requests in the api call handler in general, and it depends on the requirements of that api.
Longer version
Judging by your example: you want to update view count, and since there is no use of response of it, you don't need to await for the response. You can just fire it without await.
And structurally it would be better practice to move it to a separate function that make an actual call, or fire an event and handle it in a different place.
Moreover, it looks like you are calling the same api server, in that case it will be better just to call a function instead of the api call.
const updatePostViewcount = postId => {
// HANDLE BLOGPOST VIEWCOUNT UPDATE
}
export const loadPostHandler: RequestHandler = async (req, res) => {
// HANDLE BLOGPOST LOAD
// no await here because we don't need the response
// it will still run asynchronously
updatePostViewcount(POST_ID);
res.json({ blogPost: blogPostData }) // RES JSON THE BLOGPOST DATA
};

Using https for REST requests from inside expressjs applicaiton

From inside my expressJS application I have to verify that a cookie token is valid with a back-end server. So the relevant code involved in this is as follows:
app.get('*', (req, res, next) => {
console.log('GET: ' + req.path);
// ...
const payload = JSON.stringify({ authnToken: token });
const opts = { ... authServerOptions };
opts.headers['Content-Length'] = payload.length;
// build request
const restReq = https.request(authServerOptions, result => {
console.log('back-end response' + result.statusCode);
result.on('data', data => {
next(); // token is good now proceed.
});
result.on('error', error => {
res.redirect('somewhere'); // token is bad or timeout
});
});
restReq.write(token);
restReq.end();
}
So the main get function sets the REST request in motion and then just returns without calling next() or anything.
Questions:
Is this the right code for doing this? What happens if the callbacks are never called?
Is the application blocked from processing other requests until the back-end server returns or times out?
If so is there some way of freeing up the thread to process more requests?
Thanks in advance for any help. I haven't found many examples for this code pattern so if there is one a link would be appreciated.
Yes, I think the general idea of your implementation is correct.
I would also suggest, as done in the comments, to use a client such as axios to handle the request in a less verbose and more comprehensive manner, which would leave your code looking something like this:
const axios = require('axios');
app.get('*', (req, res, next) => {
const payload = JSON.stringify({ authnToken: token });
const opts = { ... authServerOptions };
opts.headers['Content-Length'] = payload.length;
axios.post(url, payload, opts)
.then(response => next())
.catch(error => {
console.error(error);
res.redirect('somewhere');
});
});
A bit more to the point, but functionally almost equivalent to your implementation. The one thing you are missing is the onerror callback for your request object, which currently may fail and never return a response as you correctly suspected. You should add:
restReq.on('error', error => {
console.error(error);
res.redirect('somewhere');
});
On the same vein, it would probably be more fitting to call next on result end, instead of doing so while reading response data:
result.on('end', () => {
next();
});
Then you'd be covered to guarantee that a callback would be invoked.
Neither implementation blocks the processing of future requests, as the call to the token validation service is done asynchronously in both cases.

How do you programmatically exit a node.js/express route on an event?

I want to be able to exit execution of a post route when an event is sent from the client-side. I'm using socket.io but I'm not sure it can do what I want. I am using the uploads route to process a file, but if the user deletes the file, I want the app.post execution to end, similar to either a res.end() or return statement.
My app in the front-end receives a file from the user and immediately is sent to the post route for processing. If the user deletes the file and uploads a new one, the previous post route is still going. I want to make sure the previous one was terminated, cancelled, etc.
I'm currently using socket.io to communicate front-end to back-end.
How can I achieve this?
app.post('/uploads', async (req, res) => {
// async func1
// async func2
// if we receive an event from the front end while processing here, how can I exit the post route?
// async func3
});
You can add UUID for each request you make and return it to the front-end. The request will be resolved with the 202 ACCEPTED status code meaning the request was accepted and being handled but the HTTP request will be resolved.
Now you can implement a resourceManagerServeic that will allow APIs (http or ws) to change the state of a resource (like canceling it).
app.post('/uploads', async (req, res) => {
const resourceUuid = resourceManagerServeic.createResource();
res.status(202); // ACCEPTED
res.send({ uuid: resourceUuid });
// start besnise logic
await function1();
if(resourceManagerServeic.isCanceled(resourceUuid)) {
// cleanup
return; // stop request handling
}
await function2();
if(resourceManagerServeic.isCanceled(resourceUuid)) {
// cleanup
return; // stop request handling
}
await function3();
if(resourceManagerServeic.isCanceled(resourceUuid)) {
// cleanup
return; // stop request handling
}
});
app.del('/uploads/:resourceUuid', async (req, res) => {
resourceManagerServeic.cancle(req.params.resourceUuid);
res.end() // handle response
});
I guess that your are using Express. Take a look at express-async-handler
You can invoke it
const asyncHandler = require('express-async-handler')
app.post('/upload', asyncHandler(async(req, res) => {
await firstfunc()
await secondfunc()
}))

Define/Use a promise in Express POST route on node.js

I currently have a POST route defined in an Express Node.js application as so:
var locationService = require("../app/modules/locationservice.js");
app.post('/createstop', isLoggedIn, function(req, res) {
locationService.createStop(res, req.body);
});
(for this question, please assume the routing in & db works.. my record is created on form submission, it's the response I am struggling with)
In the locationservice.js class I then currently have
var models = require('../models');
exports.createStop = function(res, formData) {
models.location.build({ name: formData.name })
.save()
.then(function(locationObj) {
res.json({ dbResult : locationObj });
});
};
So as you can see, my route invokes the exported function CreateStop which uses the Sequelize persistent layer to insert a record asynchronously, after which I can stick the result on the response in the promised then()
So at the moment this only works by passing the response object into the locationservice.js method and then setting res.json in the then() there. This is sub-optimal to me with regards to my service classes, and doesn't feel right either.
What I would like to be able to do is "treat" my createStop method as a promise/with a callback so I can just return the new location object (or an error) and deal with it in the calling method - as future uses of this method might have a response context/parameter to pass in/be populated.
Therefore in the route I would do something more like:
var locationService = require("../app/modules/locationservice.js");
app.post('/createstop', isLoggedIn, function(req, res) {
locationService.createStop(req.body)
.then(dataBack) {
res.json(dataBack);
};
});
Which means, I could call createStop from else where in the future and react to the response in that promise handler. But this is currently beyond me. I have done my due diligence research, but some individual expert input on my specific case would be most appreciated.
Your locationservice.js could look like that
exports.createShop = function(data){
// here I have used create instead of build -> save
return models.location.create(data).then(function(location){
// here you return instance of saved location
return location;
});
}
And then your post() method should be like below
app.post('/createstop', isLoggedIn, function(req, res){
locationService.createShop(req.body).then(function(location){
// here you access the location created and saved in createShop function
res.json(location);
}).catch(function(error){
// handle the error
});
});
Wrap your createStop function with a promise like so:
exports.createStop = function(res, formData) {
return new Promise(function(resolve, reject) {
models.location.build({ name: formData.name })
.save()
.then(function(locationObj) {
resolve({ dbResult : locationObj });
});
//in case of error, call reject();
});
};
This will allow you to use the .then after the createStop within your router.

Koa send status 404 every time is

export async function getPlaces(ctx, next) {
const { error, data } = await PlaceModel.getPlaces(ctx.query);
console.log(error, data);
if (error) {
return ctx.throw(422, error);
}
ctx.body = data;
}
Koa everytime sends 404 status and empty body, what i'm doing wrong ?
In seems that, await does not really "wait" and therefore returns too early (this results in a 404 error).
One reason for that could be that your PlaceModel.getPlaces(ctx.query) does not returns a promise. So it continues without waiting on results from getPlaces.
I also had this issue, and resolved it by adding :
ctx.status = 200;
directly below
ctx.body = data;
You've got to wire up your function with the router. Here's a little example how it works:
import * as Koa from "koa";
import * as Router from "koa-router";
let app = new Koa();
let router = new Router();
async function ping(ctx) {
ctx.body = "pong";
ctx.status = 200;
}
router.get("/ping", ping);
app.use(router.routes());
app.listen(8080);
in my case while using koa router i had forgotten to add
app.use(router.routes())
just above
app.listen(port)
Maybe you have middleware that is being triggered before this async function, but that middleware isn't async.
If you have any non-async middleware that gets called before this function, convert it to async.
Instead of calling next(); in the async middleware, call await next(); even if it is the last line of the middleware function.

Resources