Koa send status 404 every time is - node.js

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.

Related

Why do i get 502 Bad Gateway error in my async express.js middleware?

I have a node API which is deployed and run as a Lambda function inside AWS.
// mthd
export const validateHeaderBearerToken = (req, res) => {
if (!req.headers.authorization || req.headers.authorization.split(' ').length !== 2
|| req.headers.authorization.split(' ')[0].trim() !== authConstants.BEARER_HEADER) {
res.status(403)
.send({ message: 'Invalid token' });
throw new AuthenticationException(authConstants.NO_VALID_TOKEN_IN_HEADER_ERROR);
}
return req.headers.authorization.split(' ')[1].trim();
};
and the controller
// controller
searchApiV1Controller.use('/search/', checkAuthentication, searchRouter);
the main service
// mainService
export const checkAuthentication = async (req, res, next) => {
const bearerToken = req.headers.authorization;
logger.info(`[${getCorrelationId(req)}] Authenticating the request`);
const token = validateHeaderBearerToken(bearerToken, res);
let application='liberty';
await checkAuthorize(application);
...
}
When I pass the empty bearer token inside the header, it should respond "Invalid token" message with 403 statuscode. But Since the main service(middleware) is an async method, the call responds with 502 Bad Gateway error due to the AuthenticationException. If we remove this exception it will respond correctly with 403. But the main service method will asynchronously runs through the other sub util methods inside checkAuthentication method. So we can't remove it. What may be the solution for this?
FYI: I don't face any problems while running locally.
When using middleware chains in express, it's typically better form to use the next() function than throwing exceptions/errors. It makes them more composable and also follows the principle of not using exceptions for control flow. Exceptions are for truely exceptional cirumstances, not your standard operations.
If you pass a value to next() it will assume it's an error and skip straight to your error handling middleware. You can also add values onto the res.locals to pass it through middleware chains.
For example:
export const validateHeaderBearerToken = (req, res, next) => {
if (/* checks */) {
return next(AuthenticationException(authConstants.NO_VALID_TOKEN_IN_HEADER_ERROR));
}
res.locals.token = req.headers.authorization.split(' ')[1].trim();
};
Now because you're setting res.locals you don't need to call your validate function a in checkAuthentication, you can use it as middleware, turning that function into something like:
export const checkAuthentication = async (req, res, next) => {
// Assume res.locals.token exists, otherwise we'll have early-exited the entire request.
const bearerToken = res.locals.token
let application='liberty';
let result = await checkAuthorize(application);
// Example logic...
if (result.is_authorised == false) {
return next(/*error*/)
}
}
Now you will never call checkAuthentication if validateHeaderBearerToken fails to find a token. Your router setup will look like:
searchApiV1Controller.use('/search/', validateHeaderBearerToken, checkAuthentication, searchRouter);
Further reading on error handling in express: http://expressjs.com/en/guide/error-handling.html

My custom express json middleware is not working properly

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();
})

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.

Respond to Koa request immediately, continue middleware chain

I am writing the middleware for API endpoints in my app that respond to webhooks from other applications, and am relatively new to Koa, so am not completely familiar with its patterns.
I would like to structure my middleware as follows:
exports.updateReceived = async (ctx, next) => {
// Respond to server issuing the webhook
ctx.res.body = "ok";
ctx.res.statusCode = 200;
// Grab what we need from the request
const { headers, state, request } = ctx;
const { body } = request;
// Do some async work
const { example } = await doSomeAsyncWork(ctx);
// Prepare a database query
const query = { aValue: anId };
// Run the DB query
const result = await Thing.findOne(query);
// Add data to the request
state.thing = result;
// Move on...
return next();
};
However, this does not appear to be working, as an error in any of my async methods can cause the route to error out.
My goal is for this endpoint to always respond "yep, ok" (immediately), meaning it is simply up to the application to handle any error states.
I have researched this fairly well, and have come across this pattern:
app.use(async ctx => {
db.fetch() // Assuming a Promise is returned
.then(() => { ... })
.catch(err => {
log(err)
})
// status 200 will be returned regardless of if db.fetch() resolves or rejects.
ctx.status = 200
})
However, this does not meet my needs as the middleware makes no use of next, so it is not really a useful pattern, so far as I can tell.
Could someone tell me what I am overlooking?
next() invokes the downstream middleware chain and returns a promise that resolves after all downstream middleware/handlers have finished.
That means you can simply implement your own upstream error handler that catches any errors and always ensures a 200 OK response.
const Koa = require('koa')
const app = new Koa()
app.use(async (ctx, next) => {
next().catch((err) => {
// Print error for our own records / debugging
console.error(err)
// But ensure that outgoing response is always a smile
ctx.status = 200
ctx.body = ':)'
})
})
app.use(async (ctx) => {
// Do your webhook / biz logic here, but for demonstration
// let's make it always throw an error. Thus upstream next()
// will be a rejected promise.
throw new Error('this middleware will always bubble up a rejected promise')
})
app.listen(3000, () => {
console.log('listening on 3000')
})
Note: We are not awaiting next(), so we can end the request immediately. However the next handler in the chain will still have the opportunity to process the logic
app.use((ctx, next) => {
next()
ctx.status = 200
})
app.use( async ctx =>{
db.fetch()
.then(() => { ... })
.catch(err => log(err))
}
}
Just to divert the solution in a different side, You could consider adding your work to some kind of MessageQueue and then let another process do that task for you. Basically asynchrously but you will still be important. This kind of pattern suits for your requirement.
There are many messaging system availble like AWS SQS which you could consider. This way your api will be very light weight and it will do thing which it needs to and send a command to your messaging system to do extra stuff. You are basically separting your core logic and the doing things in background which scales very nicely as well.

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.

Resources