How to use middleware with router.verb() in koa - javascript

I'm using Koa.js and I was wondering how I could use a middleware with router.verb()
As mentioned here router.use([path], middleware) I tried like below.
The console.log() trigger but the users.list is not called
My main objective is to do an auth middleware
const Router = require("#koa/router");
const router = new Router();
const users = require("./Controllers/users/index.js");
router.use("/user", (ctx, next) => {
console.log(ctx);
next();
});
router.get("/user", users.list)
I don't get any error messages but the users.list don't execute.
Then i tried this
router.get("/user", (ctx, next) => {
console.log(ctx);
next();
}, users.list)
But i don't get any change and I feel like I don't understand something, but can't figure out what
In my index.js
const Koa = require("koa");
const router = require("./Routes");
const bodyParser = require("koa-bodyparser");
const cors = require("#koa/cors");
const serve = require("koa-static");
const path = require("path");
const errorHandler = require("./Middlewares/errorHandler");
const app = new Koa();
app.use(errorHandler)
.use(bodyParser())
.use(cors())
.use(router.routes())
.use(serve(path.join("public", "ads")))
.use(router.allowedMethods());
in my controller
const { Users } = require("../../Models");
module.exports = {
list: async (ctx, next) => {
let AllUsers = await Users.findAll();
ctx.body = AllUsers;
}
}

I got it working with adding await next()
router.use("/ads", async (ctx, next) => {
console.log(ctx);
await next();
});
Since my controller is an async function I get my explanations from here -> async/await always returns promise

Related

How can we implement an admin panel in nodeJS with express?

I am making a Portfolio application with nodeJS and express. I want to implement an admin panel which I can create,delete, update and edit my skills,experience,about etc, but I don't know how can I keep those admin routes secret and what kind of authentication to make.If we can do by putting Basic authentication on post,patch,delete route then how will we implement basic authentication on routes.
index.js
const express = require('express');
const app = express();
var cors = require('cors');
require('./db/mongoose')
const menuRouter = require('./routers/menu')
const skillRouter = require('./routers/skill')
const aboutRouter = require('./routers/About')
const experienceRouter = require('./routers/Experience')
const resumerouter = require('./routers/Resume')
const userRouter = require('./routers/user')
const port = process.env.PORT || 4000;
app.use(express.json());
app.use(cors());
app.use(menuRouter);
app.use(skillRouter);
app.use(aboutRouter);
app.use(experienceRouter);
app.use(resumerouter);
app.use(userRouter)
app.listen(port, () => {
console.log("Server is runing on port" + port)
});
skill.js
const express = require('express');
const Skill = require('../model/skill');
const router = new express.Router();
router.post('/skill', async (req, res) => {
const skill = new Skill(req.body);
try {
await skill.save();
res.status(201).send(skill);
} catch (e) {
console.log(e);
res.status(400).send(e);
}
})
router.get('/skill', async (rq, res) => {
try {
const skill = await Skill.find({});
res.status(201).send(skill);
} catch (e) {
res.status(400).send(e);
}
})
module.exports = router;
As specified in the comments, I would refactor your code a bit, seems messy and you're kind'a repeating yourself every line you import a route, so, you should do it better as well...
have an index.js file in your /routers folder with the content of the demo repo I've made for other StackOverflow question
then, to separate things, I would do something like:
const routes = require('./routes')
...
const protectRouteWithApiKey = (req, res, next) => {
const auth = req.headers['x-apikey']
if (auth && auth === '<YOUR API KEY>') return next()
return next(new Error('403 | Authorization is missing or value is wrong'))
}
...
app.use('/api', protectRouteWithApiKey, routes) // point to your routes and protect access
app.use('/', defaultEngine) // your engine to render html
you would then have a protected route in /api/* and normal routes for everything else
A middleware where you detect if the logged user is the admin?
In this sample checking by the email, and you can save the adminemail as a global variable
ensureAdmin: function(req, res, next) {
if (req.isAuthenticated()) {
if (req.user.email === adminemail) {
return next();
} else {
return res.redirect('/adminsecretroute');
}
}
res.redirect('/');
}

Route.delete() requires a callback function but got a [object Object]

I have node-express app where I have bunch of Routes for login, logout and signup and one Route for checking authorised Route which can be accessed only through providing authToken. I moved the Routes to separate Route file and I got the above error.
This is my Users Routes File:
const express = require('express');
const authenticate = require('./../middleware/authenticate');
const router = express.Router();
const {User} = require('./../models/user');
router.post('/',(req, res) => {
var body = _.pick(req.body,['email','password']);
var user = new User(body);
user.save().then(() => {
return user.generateAuthToken()
}).then((token) => {
res.header('x-auth', token).send(user);
}).catch((e) => {
res.status(400).send(e);
});
});
router.post('/login',(req, res) => {
var body = _.pick(req.body, ['email', 'password']);
User.findByCredentials(body.email, body.password).then((user) => {
return user.generateAuthToken().then((token) => {
res.header('x-auth', token).send(user);
});
}).catch((e) => {
res.status(400).send(e);
});
});
router.delete('/logout',authenticate, (req, res) => {
req.user.removeToken(req.token).then(() => {
res.status(200).send();
},(e) => {
res.status(400).send(e);
}) ;
});
router.get('/me',authenticate, (req,res) => {
res.send(req.user);
});
module.exports = router;
Following is my main server.js file:
const express = require('express');
const _ = require('lodash');
var app = express();
const usersRoutes = require('./routes/users');
app.use(express.json());
app.use('/users', usersRoutes);
var {mongoose} = require('./db/mongoose');
var {User} = require('./models/user');
var {authenticate} = require('./middleware/authenticate');
const port = process.env.PORT || 3000 ;
app.listen(port, () => console.log(`Listening on ${port}...`))
I have a model/Schema(mongoose) file for User so If You feel you need that I am ready to edit my question. Thanks.
The problem is that router.delete is expecting a function on the middleware parameter (like you did in your server.js file with app.use(express.json())) so it can be used like a callback which gets called whenever a request reach your route.
Try changing authenticate to authenticate().
It seems like in your users routes file you are importing the entire module who contains the authenticate function, so when try to access it like a function you'll get an error. You need to import it like you did in your server.js file.
Change the line const authenticate = require('./../middleware/authenticate'); for const {authenticate} = require('./../middleware/authenticate');.

How to save a variable before serving a file in nodejs

given the following code:
const https = require('https');
const fs = require('fs');
var path = require('path');
const express = require('express');
const app = express();
const router = express.Router();
const pool = require('./mysqldb.js');
const pathView = __dirname + "/views/";
const IMGPath = "/public";
var bodyParser = require("body-parser");
const listenPort = 8010;
var id = null ;
router.get('/details/:id', async function (req, res, next) {
id = req.params.id;
if ( typeof req.params.id === "number"){id = parseInt(id);}
res.render('details.ejs' );
});
The main goal is to save that req.params.id(the id from the url) in the id variable before serving the details.ejs file.I tried to remove the async but didn't work.Can you help me please?
You can make use of the await keywords inside your async function like so:
router.get('/details/:id', async function (req, res, next) {
await (() => { id = req.params.id; })(); // Will run first
await (() => { res.send(id); })(); // Will run second
})
res.send(id) or res.render('details.ejs') ( in your case ) will run after the id is retrieved
It seems to be working fine for me. Below, I launch this server, then I go to http://localhost:3050/123 and suddenly I'm console.logging '123' over and over again, and the correct text displays on the screen.
So... idk what else if going on for you, but it might help if you try your best to distill your code down to the simplest possible iteration to try to debug. Just try to replicate it elsewhere. You might find one of your additional modules is causing an issue.
const express = require('express')
const app = express();
const port = 3050;
let id = null;
app.get('/:id', (req, res) => {
return res.send('Hello World!')
});
app.get('/details/:id', (req, res) => {
if (req.params.id){
id = req.params.id;
}
// 'id' will appear in browser
return res.send(`See details for id: ${id}`);
});
// console logs of 'id'
setInterval(() => { console.log(`id is currently ${id}`); }, 1000);
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I don't think async/await will have any effect on this specific issue. I doubt they're related.
This seems to work for me,
router.get('/details/:id', async function (req, res, next) {
id = typeof req.params.id === 'number' ? parseInt(id) : req.params.id;
console.log(id);
res.send('details.ejs' );
});

Firebase Cloud Function Auth Trigger not firing

I'm using Express in my Cloud Function with multiple routes, and I'm trying to add in a function that when triggered, will pull the users Gravitar and add it to their user object.
The problem I'm having is that I cannot get the onCreate function to fire, and I suspect it's to do with how I'm attempting to export it.
My index.js looks like the following:
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const usersApi = require("./api/users")
const paymentsApi = require("./api/payments")
const express = require('express');
const cors = require('cors');
const app = express();
const checkHeader = async(req, res, next) => {
if(req.headers.authorization) {
admin.auth().verifyIdToken(req.headers.authorization)
.then(token => {
req.uid = token.uid;
req.email = token.email;
req.stripeID = token.stripeID || null;
return next();
})
.catch(e => {
return next(e.errorInfo.code)
})
} else {
return next('No token found');
}
}
app.use(cors({origin: true}));
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(checkHeader);
app.disable("x-powered-by");
app.use("/users", usersApi)
app.use("/payments", paymentsApi)
const setupUser = functions.auth.user().onCreate((user) => {
console.log("onCreate")
console.log(user)
})
module.exports = {
api: functions.https.onRequest(app),
setupUser
}
The api endpoint works fine, however I can't get the onCreate function to trigger when a user is created.

Why does 'koa-static' middleware keeps returning 404?

I'm trying Koa by using koa-static. But it keeps returning 404 (Body: Not Found) when using multilevel inclusion relationship. I don't know the reason.
To reproduce,
Windows 10 x64, Node v9.11.1
Koa v2.5.1, koa-compose v4.1.0, koa-static v4.0.3, koa-send v4.1.3
Directory:
index.html   index.js   sites/sites.js   sites/onesite/index.js
index.html
Hello, koa
index.js
const Koa = require('koa')
const router = require('./sites/sites.js')
const app = new Koa()
app.use(router())
app.listen(80)
sites/sites.js
const compose = require('koa-compose')
module.exports = ()=>{
return (ctx, next)=>{
compose(require('./onesite').middleware)(ctx, next)
}
}
sites/onesite/index.js
const Koa = require('koa')
const serve = require('koa-static')
const app = new Koa()
app.use(serve('.'))
module.exports = app
Your problem is in the router you return from sites.js:
module.exports = ()=>{
return (ctx, next)=>{
compose(require('./onesite').middleware)(ctx, next)
}
}
compose is an async function, but you do not wait for its promise to finish. One way to solve this is to return the promise that is returned by compose so that koa knows that it has to wait for that promise to be resolved:
module.exports = ()=>{
return (ctx, next)=>{
return compose(require('./onesite').middleware)(ctx, next)
}
}
Another way would be to use await:
module.exports = ()=>{
return async (ctx, next)=>{
await compose(require('./onesite').middleware)(ctx, next)
}
}

Categories