Node js: using model-like code outside of the model - node.js

I'm trying to write a small api with Facebook authentication and as I'm new to node.js I'm just a little confused as to how I should structure this.
I have a route called auth.js that looks like this:
var express = require('express');
var crypto = require('crypto');
var rp = require('request-promise');
var router = express.Router();
router.post('/', function(req, res) {
rp('https://graph.facebook.com/me?access_token=' + req.body.fbAccessToken).then(function(body) {
var json = JSON.parse(body);
if(json.error) { res.status(403).send(json.error.message); }
var user = new User({
userId: json.id,
fbAccessToken: req.body.fbAccessToken,
apiAccessToken: crypto.randomBytes(64).toString('hex'),
firstName: json.first_name,
lastName: json.last_name,
email: json.email
});
user.save(function(err) {
if (err) throw err;
return user.userId;
});
}).then(function(userId) {
res.status(201).send('something');
}).catch(function(err) {
res.status(403).send(err);
});
});
module.exports = router;
When the route recieves a post it takes the Facebook token from the request and checks if it is legit using the Facebook graph API. (Apologies if the Promise stuff looks a little funky too, I'm trying to learn that as well).
Anyway, I have a User model and a user.js route too. What I want to know is if the User creation that happens in my auth route here should be moved to the User model and the model functions called from here somehow? Via the user route maybe?
Cheers

Yes and yes. I think user stuff can go under /user and it is cleaner if the user creation is in its own module.
BTW did you see fbgraph?

Related

How to hash a password with bcrypt in mongodb without a page for registration?

I have a problem. I would like to register a user in my mongodb with bcrypt directly (without have a UI for client, I want to manage it directly with querys) and login with REST API from client. It is possible or not?
Thanks!
Definitely, you can have a Node API running and then send a POST request to an endpoint you define with Postman for example:
// Routes file. Import this file later in your app.js or index.js file
const express = require('express');
const router = express.Router();
/* ..... also import any user model, file, etc....*/
router.post('/signup', (req,res,next)=>{
const username = req.body.username;
const password = req.body.password;
bcrypt
.hash(password, 12)
.then(hashedPassword => {
/* Your MongoDB logic. Example below */
const user = new User({ // Example if you had a User Model
email: email,
password: hashedPassword
});
return user.save();
})
.then(result => {
// To be more RESTful this should send the whole user in JSON format after creation**
res.status(201).json({ message: 'User created!'});
})
})
.catch(err => {
// Error logic. This is just an example
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
});
module.exports = router;
To make it clearer you should have a controllers file too. If you also want a login then the logic would be similiar, create an endpoint and then send a request with Postman or some other app.

Post request never getting made, just sends get

I am using Mongoose and nodejs to write an API.
My users.js looks as follow:
var express = require('express');
var router = express.Router();
var user = require('../models/users.js');
router.post('/',function(req, res, next) {
console.log("made a post");
var user2 = new user(); // create a new instance of the Bear model
user2.firstName = req.body.firstName; // set the bears name (comes from the request)
user2.lastName=req.body.lastName;
user2.email=req.body.email;
user2.save(function(err) {
if (err)
res.send(err);
console.log("User created");
});
})
//The model acts as our user object...this returns all users.
.get('/', function(req, res, next) {
console.log("sending a get request");
user.find(function(err, users) {
if (err)
res.send(err);
res.json(users);
});
})
module.exports = router;
When I send a get request, it works perfectly. However, I am now trying to develop the POST request. I send a request such as the following:
http://localhost:4000/users?firstName=Han&lastName=Bo#email=haBo#yah.com
and I receive the following in my console:
sending a get request
GET /users?firstName=Han&lastName=Bo#email=haBo#yah.com
200 15.522 ms - 1365
And I receive the output of my GET request in the browser.
I'm new to node and would appreciate some help with this.
Thanks.
You are putting your parameters as URL parameters, while your POST API reads parameters from body of request.
Here is explanation of POST parameters.
Also, if you are not already using it, use postman to send requests.

how to access db from node.js middleware

I want to verify that a user has a role which allows him/her to use an endpoint in my API. Usually I would go about doing so by taking the userId sent as part of a JWT and do a lookup on the DB to see what the user's role is. It would happen inside an API call and would look something like this:
var userId = getUserIdFromJwt();
app.models.User.findOne({_id: userId}, function (err, user) {
...check if user is in role...
});
Now I want to try and move that code to a piece of middleware, which would look like this:
exports.isUserInRole = function(app, allowableRoles) {
var userId = getUserIdFromJwt();
app.models.User.findOne({_id: userId}, function (error, user) {
if (error) {
return res.status(500).json(error);
}
return function (req, res, next) {
if(_.includes(allowableRoles, user.Role)) {
next();
} else {
return res.status(401).json({"error": "User not in role"});
}
}
});
};
The middleware would be implemented like this:
const allowableRoles = ['admin', 'implementor'];
app.get('/getStuff/', isUserInRole(app, allowableRoles), function (req, res) {
... do stuff if user is in role ...
});
At this point I am running into a problem where the app.models.User value is always undefined.
I do not understand why app.models.User is undefined at this point as I can access it within the anonymous function inside the get call.
How would I go about about access the DB from within my middleware if I cannot send it app.models.User?
For reference, I am using Mongoose and exposing it to my app in the server.js from which I access the a MongoDB db.
I think you're problem is that you are trying to get models before they are actually initialized, as you are binding the app to the parameters on initialization of the app.
So in your main app file, I would do module.exports = app; and then in your middleware file, simply include the app by doing var app = require('./path/to/app');. Then remove the app from the middleware. You might end up with something like this:
var app = require('./path/to/app');
exports.isUserInRole = function(allowableRoles) {};
And in your route change it to this:
const allowableRoles = ['admin', 'implementor'];
app.get('/getStuff/', isUserInRole(allowableRoles), function (req, res) {}
And lastly in your app file, add the app to the exports:
module.exports = app;
EDIT:
If you're using Mongoose, you can also do something more simple like this:
var mongoose = require('mongoose');
var User = mongoose.model('User');
My first guess would be b/c you are actually calling the function instead of just passing it in. Additionally, you're not actually passing in middleware. Middleware functions look like
function(req,res,next){}
Additionally, you probably want to leverage sessions instead of hitting the database on each request

Express.js database and validation logic. Where?

Nothing important
My first question here on stackoverflow. I've used it for years to find answers, but now I need a bit of guidance. I'm new to node and express and the async way of structuring an app.
Goal - A REST interface with validation and neDB database
I got the following code working. POST a new user is the only route. It's based on many answers and tuts mixed together. I find it hard to scaffold out the logic, to get a structure you can build on.
I'm not sure at all whether this structure is crap or not. Any advice would be appreciated.
Main file is initializing the database, middleware validator, and starting the app.
// rest.js
var express = require('express'),
bodyParser = require('body-parser'),
validator = require('express-validator'),
db = require('./database/db'),
userRouter = require('./routers/users');
db.init();
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(validator());
app.use('/api/users', userRouter);
var port = process.env.PORT || 8080;
app.listen(port);
Database
This question/answer made me create the small database module with alterations.
How do you pass objects around node express application?
It doesn't have much attention. Maybe because it's very obvious or maybe not a good answer.
The idea is that whem i get multiple collections, they all get initialized on startup, but I can request a single collection if that's all the module needs, or I can get the entire db object back if another module would require that.
// database/db.js
var nedb = require('nedb');
var db = {};
db.init = function() {
db.users = new nedb({ filename: './database/data/users', autoload: true });
db.users.ensureIndex({ fieldName: 'username', unique: true }, function (err) {});
db.users.ensureIndex({ fieldName: 'email', unique: true }, function (err) {});
};
db.get = function(collection) {
if (collection && db[collection])
return db[collection];
return db;
}
module.exports = db;
Router
I require the User Model here and use the express-validator and sanitizes the request before passing it on to the model, based on a minimalist key schema in the model. I don't have any controllers. If I had (or when I do), I would put the validation there. The router is supposed to send the response and status right?
// routers/users.js
var express = require('express'),
_ = require('lodash'),
User = require('../models/user');
var userRouter = express.Router();
userRouter.route('/')
.post(function(req, res) {
req.checkBody('username', 'Username must be 3-20 chars').len(3,20);
req.checkBody('email', 'Not valid email').isEmail();
req.checkBody('password', 'Password must be 6-20 chars').len(6,20);
var err = req.validationErrors();
if (err) {
res.status(422).send(err);
return;
}
var data = _.pick(req.body, _.keys(User.schema));
User.create(data, function (err, newData) {
if (err) {
res.status(409).send(err);
} else {
res.status(201).send(newData);
}
});
});
module.exports = userRouter;
Model
The model requires the database module and gets the "connection". Is this OK?
// models/user.js
var db = require('../database/db');
var User = function (data) {
this.data = data;
};
User.schema = {
_id: null,
username: null,
email: null,
password: null
};
User.create = function (data, callback) {
db.get('users').insert(data, callback);
};
module.exports = User;
Thanks for reading this far. Now, my question is:
Is there something fundamentally wrong with this setup, concerning the database usage and the validation logic. I know the model looks stupid :)

Best Way to Use OOP in Express REST API?

I'm going all in and doing a project using only node. It's been a lot of fun, but sometimes I get a little lost in it and I want to try to gain understanding as I get confused so I build it correctly and don't get too overwhelmed. Anyway, here's the problem:
I have REST API that's using Express and mysql. I set up mysql:
app.js
//Variables, move these to env
var dbOptions = {
host: config.db_config.host,
user: config.db_config.user,
password: config.db_config.password,
port: config.db_config.port,
database: config.db_config.database
};
app.use(myConnection(mysql, dbOptions, 'single'));
and then I include my routes, passing the routes the app and log middleware so I can use them in the route:
app.js cont.
var userRoute = require('./routes/users.js')(app,log);
app.use('/users', userRoute);
That actually was a little confusing, but now I get it, I have to pass them into module in order for the module to get the data.
Then in my route file I want to use an object so that I can use the same functionality in other routes, but in the user file in order to use the same connection pool that everything else is using, or at least to not have to set up the connection again I have to pass it the response and request? There's gotta be a better way to do that. It's really ugly that way. Here's the relevant part of
routes/users.js
var User = require('../controllers/User.js');
module.exports = (function(app,log) {
var userR = express.Router();
userR.post('/register', function(req,res){
var email = req.body.email;
var password = req.body.password;
var firstName = req.body.first_name;
var lastName = req.body.last_name;
var userId;
try {
var query;
var status = 200;
var response = '';
var newUser = {
email: email,
password:password,
first_name: firstName,
last_name: lastName,
password: password
};
var user = new User(req,res);
user.register(newUser);
...
};
controllers/User.js
module.exports = function User(req,res) {
this.id = 0;
this.register = function(newUser){
var _this = this;
var deferred = q.defer();
req.getConnection(function(err,connection){
...
There must be a pattern I'm missing here. I should just be able to pass the app or something and have access to the req.getConnection etc.
Thanks.
There's kind of a lot going on here, but I'll take a crack at this one.
My first recommendation would be to try to keep your routers pretty slim. It's not labeled, but I'm assuming the largest snippet of code you've provided is your router. There are lots of opinions of course, but if I were doing this here's what my router would look like. I'm assuming you're using Express 4x.
routes/users.js
var User = require('../controllers/user.js');
var userRouter = express.Router();
userRouter.post("/register", User.register);
module.exports = userRouter;
So what we've done here is eliminated the dependency on your app/log middleware.
This means your main file (what I usually call app.js), will look like this:
app.js
var userRouter = require('./routes/users.js');
app.use('/users', userRouter);
This is also where you can put any middleware you chose (logging, body-parsing, error-handling, etc).
In the later versions of Express the above code actually mounts our userRouter to "/users". In this case you will now have a "/users/register" route.
So now since we've pulled out some of the logic of the router, we have to put that somewhere. Typically a router will talk to a controller so let's take a look:
controllers/user.js
var User = require("../models/user.js")
var register = function(req, res, next){
var email = req.body.email;
var password = req.body.password;
var firstName = req.body.first_name;
var lastName = req.body.last_name;
var userId;
var params = {
email: email,
password:password,
first_name: firstName,
last_name: lastName,
password: password
};
var newUser = new User(params);
try {
newUser.register();
// do other things...
}
};
module.exports = {register: register};
The first thing you'll notice is that I would have a UserModel file. By doing this, we've de-coupled our model object from this route. Let's say for instance we have a new register route (maybe one of them has an email + pw, the other registers through FB and we have to store different things). We should be able to use the same function (user.register in this case) specified in our model without having to change a whole bunch of things!
Now, here's what a UserModel might look like:
/models/user.js
var connection = require("../lib/connection.js");
var User = function(params){
this.email = params.email;
// ...etc
};
User.prototype.register = function(newUser){
connection.getConnection(function(error, connection){
//connection.doWhatever();
});
};
module.exports = User;
Now we've finally gotten to the core of your question. At the top, you'll see we have a connection file. This is where we're going to put all of our DB-related logic like our connection pools.
/lib/connection.js
/*
This will be in some JSON config we'll say
var dbOptions = {
host: config.db_config.host,
user: config.db_config.user,
password: config.db_config.password,
port: config.db_config.port,
database: config.db_config.database
};
*/
//This will depend on which version/module/db you're using, but here's what mine looks like
var MySQL = require("mysql");
var config = require("../config/db.json");
connectionPool = MySQL.createPool({host: config.db_config.host, ...});
var getConnection = function(done){
connectionPool.getConnection(done);
};
module.exports = {getConnection: getConnection};
So, in conclusion, instead of passing your connection along with your request object, we now simply include our short connection module in whichever model file we're in, kindly ask for a connection, and do whatever processing we need to. Also note you'll have to release the connections back into the pool, but I'll leave that as an exercise for you :).
Also, I usually write CoffeeScript, so please excuse any small errors. Let me know if you have need for further clarification.
Cheers,
Brennan

Resources