I am making an api with Koa:
This is the router handler: (assume I have router.get(..., get) and app.use(router.routes())
async function get(ctx, next){
console.log(ctx.response)
let user = await getUser(1);
ctx.body = {
data: user || [],
message: ctx.response.status
}
}
The api returns the user but I've noticed that even tough it matches the route, the data is returned as JSON and on the browser the response is 200, when I log the response is 404.
Is this a bug or more configuration is needed?
I am using Koa 2 (@next)
you should log after ctx.body=, this line will change the response's status from 404 to 200
@dead-horse How do you get the response code to be returned on the api? thanks
async function get(ctx, next){
let user = await getUser(1);
ctx.body = {
data: user || [],
message: ctx.response.status
};
console.log('the response status is ', ctx.status);
}
@dead-horse I am having this same issue
router.post("/send", async ctx => {
const ctl = require("./controllers/Messages");
ctx.body = await ctl.send(ctx);
});
//controllers/Messages.js
this.send = async ctx => {
return await emailService.sendEmail(ctx.request.body);
};
It returns 400. And if I add a log(console.dir(ctx.body)) after the ctx.body = await ctl.send(ctx); line, it outputs the resolved value from the async call.
Please help
Figured this out from another thread. Basically, you need to search all your middleware functions and make sure that they are all async functions(Yes! Every single one of them attached to Koa).
In addition to the above answer by @Oyelaking, make sure that none of your middlewares are prematurely returning without data.
In my case, I was calling jwt.verify without returning anything.
module.exports = async (ctx, next) => {
const token = ctx.cookies.get('token');
jwt.verify(token, config.auth.jwtSecret, (err, payload) => {
if (err) {
ctx.throw(401, {
data: {
error: 'UNAUTHORIZED',
message: 'Invalid token.'
}
});
} else {
return next();
}
});
}
As you can see, I'm just calling jwt.verify() and I only call next() within a callback. This gets separated onto its own 'thread' and the middleware returns prematurely with no data on ctx.body.
I solved it by calling jwt.verify() with async/await.
try {
await jwt.verify(token, config.auth.jwtSecret);
return next();
} catch(err) {
ctx.throw(401, {
data: {
error: 'UNAUTHORIZED',
message: 'Invalid token.'
}
});
}
@jemhuntr Thanks very much, this was messing with my head 馃様
I had a similar issue where I forgot to await my next() call:
.get('/*', async (ctx, next) => {
validate(ctx.request.body);
next(); // Should be await next();
})
.get('/some-route', async (ctx, next) => {
ctx.response.body = 'some ok response';
// Code here will execute, but have no influence on the response as it has already 'returned'.
// Based on the route above, all subsequent routes will return 404s.
})
Figured this out from another thread. Basically, you need to search all your middleware functions and make sure that they are all async functions(Yes! Every single one of them attached to Koa).
Thanks for your guidance!鉂わ笍
But if I've attached my middleware to a route like this
because I want to use this middleware only this route!
const validationMw = (dtoClass: any) => {
return async function (ctx: RouterContext, next: () => Promise<any>): Promise<void> {
const transformedData = plainToClass(dtoClass, ctx.request.body)
try {
await validateOrReject(transformedData)
await next()
} catch (errors) {
if (errors.length > 0) {
let errorTexts = <any>[]
for (const errorItem of errors) {
errorTexts = errorTexts.concat(errorItem.constraints)
}
httpBadRequest(ctx, errors[0].constraints)
}
}
}
}
// Route
router.post('/assets', validationMw(AssetRequestDto), createAssetController)
What should I do !?
This problem can also be solved by specifying the middleware in this fashion:
app.use(async (ctx) => (ctx.body = 'Hello'));
Most helpful comment
Figured this out from another thread. Basically, you need to search all your middleware functions and make sure that they are all async functions(Yes! Every single one of them attached to Koa).