I'm curious if anyone could provide some insight on the best way to abstract an API built with Node.js + Restify + Mongoose. After coming from an MVC / PHP background, it's interesting to find that there's not string/defined structure for Node applications.
As of now, I have my app.js file that auto loads my routes.js file, all model js files, etc.
The confusion is primarily in how my routes are supposed to interact with data from Mongo. Here is a basic rundown on how my code is layed out.
app.js:
/**
* Require Dependencies
*/
var restify = require('restify')
, mongoose = require('mongoose')
, config = require('./config')
, routes = require('./routes');
/**
* Create Server & Define Settings
*/
var server = restify.createServer({
name: config.name,
version: config.version
});
/**
* Common Handlers
*/
server.use(restify.acceptParser(server.acceptable));
server.use(restify.queryParser());
server.use(restify.bodyParser());
server.use(restify.jsonp());
/**
* Connect to Mongo Database
*/
mongoose.connect(config.mongo.uri, function(err) {
// assign connection to var so we can pass it down the chain
var db = mongoose.connection;
// handle connection error
db.on('error', console.error.bind(console, 'connection error:'));
// handle connection success
db.once('open', function callback () {
/**
* Start Routing API Calls
*/
routes.route(server, db);
});
});
/**
* Start Server & Bind to Port
*/
server.listen(config.port, function () {
console.log('%s v%s listening on port %s in %s mode.', server.name, server.version, config.port, config.env);
});
routes.js:
module.exports.route = function(server, db) {
var Users = require('./models/users.js');
/**
* Users
*/
server.get('/users', function (req, res, next) {
res.send(Users.list(db, req, res));
return next();
});
server.get('/users/:user_id', function (req, res, next) {
res.send(Users.get(db, req, res));
return next();
});
}
models/users.js:
// fake database
var users = [
{
name: 'Nick P',
email: 'nick#domain.com'
},
{
name: 'Zack S',
email: 'zack#domain.com'
}
];
exports.list = function(db, req, res) {
return users;
};
exports.get = function(db, req, res) {
return users[req.params.user_id];
};
As you can see, I'm using a "fake database" that is a simple object. Where / how could I introduce a Mongoose layer to communicate with our database? I'm mostly concerned with how I should use schemas and exports. Any code examples, or direction would be awesome.
Here a simple example of what I usually do with Express, it's kind of the same thing with Restify. You can manage your Mongoose schemas in the same way but in your Restify routes.
app.js :
var express = require('express');
var app = express();
app.configure(function () {
app.use(express.logger('dev'));
app.use(express.bodyParser());
});
// connection to mongoDB
var mongoose = require('mongoose');
mongoose.connect('mongodb:mongoURI');
var user = require('./routes/users');
app.get('/users/list', user.list);
app.listen(3000);
models/user.js :
var mongoose = require('mongoose')
,Schema = mongoose.Schema
,ObjectId = Schema.ObjectId;
var userSchema = new Schema({
id: ObjectId,
name: {type: String, default: ''},
email: {type: String, default: ''}
});
module.exports = mongoose.model('User', userSchema);
routes/users.js :
var User = require('../models/user.js');
exports.list = function(req, res) {
User.find(function(err, users) {
res.send(users);
});
};
Related
I'm building a pretty simple API to do a basic CRUD operations on a local mongo database. The code looks fine for me but somehow the CRUD operations results on a pending request which never ends.
Here the parts of the code:
spawn.model.js (Model corresponding to database collection)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SpawnSchema = Schema({
Name: {
type: String,
unique: false,
required: true
}
}, { timestamps: true });
module.exports = mongoose.model('spawns', SpawnSchema);
spawn.controller.js
var Spawn = require('../models/Spawn/spawn.model');
exports.getSpawns = function(req, res){
Spawn.find({}, function(spawns){
res.send(spawns);
});
}
Here the spawn.routes.js file:
var Spawns = require('../controllers/spawn.controller');
module.exports = function(app){
app.get('/list', Spawns.getSpawns);
}
And then finally the server.js file:
var express = require('express');
var bodyParser = require('body-parser');
var properties = require('./config/properties');
var db = require('./config/database');
var app = express();
//configure bodyparser
var bodyParserJSON = bodyParser.json();
var bodyParserURLEncoded = bodyParser.urlencoded({ extended: true });
// call the database connectivity function
db();
// configure app.use()
app.use(bodyParserJSON);
app.use(bodyParserURLEncoded);
// Routes
app.get('/', function(req, res){
res.json({ message: 'Spawns API' });
});
require('./app/routes/spawn.routes')(app);
// intialise server
app.listen(properties.PORT, () => {
console.log(`Server is running on ${properties.PORT} port.`);
})
The database file on ./config is the following:
var mongoose = require('mongoose');
var dbURL = require('./properties').DB;
mongoose.Promise = global.Promise;
module.exports = function(){
mongoose.connect(dbURL, { useNewUrlParser: true }, function(){
console.log('Successfully connected to database');
});
}
And the properties.js on /config is simply an object with the database URL and the port for the express server.
When I try to to a request through Postman to the URL: http://localhost:4000/list the request gets hanged and never resolves. What am I missing?
PD: SOLVED!
===========
I needed to update mongoose version on npm cause it was 3.x and needed to be 5.x in order to work well with the new methods.
Update your code little bit, Like this and check
spwanRoute.js
const express = require('express');
const router = express.Router();
const spawnCntr = require('./speanControllers');
router.get('/list', spawnCntr.getSpawns);
module.exports = router;
spwanUtils.js
const Spawns = require('../models/Spawn/spawn.dao');
const spawnUtils = {};
spawnUtils.getSpawns = (req, res) => {
try {
Spawns.get({}, (err, spawns) => {
if(err){
return res.status(400).json({ error: err });
}
return res.status(200).json({ spawns });
});
} catch (err) {
console.log(err);
return res.status(500).json({ error: 'INTERNAL_EROR' });
}
}
module.exports = spawnUtils;
I am very new to node JS and mongo.
I am working on a personal website that stores a user's information in my database.
For simplicity, let's say I have the following form in jade...
form(class="inputs", action="/login", method="post")
input(type="text", name="email",class="form-control", id="emailLogin", placeholder="Queen's Email")
I already set up a database, and I was able to connect to it using the following javascript...
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/user');
var db = mongoose.connection;
db.on('error', console.error);
db.once('open', function() {
// Create your schemas and models here.
});
I want to store the input from email for every user that registers using the form above.
I am guessing I would first have to create a schema, which would probably look like this, but I'm not sure...
var Schema = mongoose.Schema;
var userSchema = new Schema({
email: String
});
//I think I have to create a model too?
And to get POST data I think I would need some code that looks like this...
app.post('/login', function(request, response){
//I am not sure what to put inside
});
My question is, can someone show me how to implement all these together so that every time a user registers with their email, it is saved in the database. It is very hard to research this, and have tried and failed many times.
EDIT
Here is my index.js file...
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'QChat' });
});
module.exports = router;
Also, here is another file in my routes directory called users.js, I'm not sure what its purpose is...
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
Here are some sample codes, hope it could help you.
var userSchema = new Schema({
email: String
});
var User = mongoose.model('User', userSchema);
app.post('/login', function(request, response){
var u = new User({
email: request.body.name
});
u.save(function(err) {
if (err)
throw err;
else
console.log('save user successfully...');
});
});
Also to parse the post url correctly, express could be used here, sample codes as below.
var bodyParser = require('body-parser')
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
user.model.js
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, Q = require('q')
;
var UserSchema = mongoose.Schema({
email: String,
})
UserSchema.methods.Save = function() {
return Q.ninvoke(this, 'save');
}
var User = mongoose.model('User', UserSchema);
user.controller.js
var mongoose = require('mongoose')
, User = mongoose.model('User')
;
app.post('/create', function(request, response){
var user = new User();
user.email = request.body.email;
return user.Save().then(function(users) {
// some code if save succeed
}, function(err){
// some code if save failed
});
});
Hi i am developing nodejs application with express and mongodb.So i must define mongoose and schema in my all routing js to use mongo and schema. I want to define them only ones. I am new at node.js so please be patient. My project structure:
My route.js is shown below:
var routes = function (app) {
app.locals.error=null;
app.get('/login', function (req, res) {
return res.render(__dirname + "/views/login", {
title: 'Giriş',
stylesheet: 'login'
});
});
var mongoose = require('mongoose');
mongoose.connect("mongodb://localhost/fuatblog");
var UserSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
age: Number
}),
Users = mongoose.model('Users', UserSchema);
app.post('/sessions', function (req, res) {
console.log(req.body.login.email);
console.log(req.body.login.password);
console.log(req.body.login.rememberMe);
Users.find({
email: req.body.login.email,
password: req.body.login.password
}, function (err, docs) {
if (! docs.length) {
// no results...
console.log('User Not Found');
res.status(400);
return res.render(__dirname + "/views/login", {
title: 'Giriş',
stylesheet: 'login',
error: 'Kullanıcı adı veya şifre yanlış'
});
}
console.log('User found');
req.session.email = docs[0].email;
console.log(req.session.email);
return res.redirect('/Management');
});
});
};
module.exports = routes;
And my server.js(app.js)
/**
* Module dependencies.
*/
////Mongoose eklendi
var express = require('express'),
mongoose= require('mongoose');
var http = require('http');
var path = require('path');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
////Cookie için eklendi.
app.use(express.cookieParser());
////Session desteği için eklendi
app.use(express.session({secret: 'asdfsdfsafasdfasdfasdf'}));
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
////Put ve Delete mothodları için
app.use(express.methodOverride());
////Requeestleri ayrıştırmak için kullanılıyor
app.use(express.bodyParser());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
////Helpers
//require('./apps/helpers')(app);
//Routes
require('./apps/authentication/routes')(app)
require('./apps/blog/routes')(app)
require('./apps/management/routes')(app)
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
I'm going to assume that you meant that you want to define the Schema only ONCE.
What I like to do is to initialize all the models that I'm going to use when the server starts and the mongodb connection is established.
An ideal directory structure would be something like this:
mongodb
--schemas
----user.js
--models.js
You would put your schemas inside the schema folder, such as your User model:
(user.js)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports = function() {
var UserSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
age: Number
});
mongoose.model("User", UserSchema);
};
In models.js, you would have code that initializes each schema model in the schemas directory.
(models.js)
exports.initialize = function() {
require("fs").readdirSync(__dirname + "/schemas").forEach(function(file) {
require('./schemas/' + file)();
});
};
In your app.js file, you would do this call to initialize all your schemas AFTER you establish your connection to mongoose:
require($pathToYourModelsJsFile).initialize();
After this, you are all set to use your models! All you have to do for when you want to use them is:
var mongoose = require('mongoose');
var User = mongoose.model('User');
// Do work
User.find();
I made an express app, and it has an app inside of that called users. I am using Typescript. This is what my app.js file looks like:
///<reference path='d.ts/DefinitelyTyped/node/node.d.ts' />
///<reference path='d.ts/DefinitelyTyped/express/express.d.ts' />
///<reference path='routes/Users.ts' />
import express = require("express");
import http = require("http");
import path = require("path");
import us = require("./routes/Users");
var app = express();
// all environments
app.set('port', 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.set('env', 'development');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', (req, res) => {
res.render("index", {
title: "Express Main Page"
});
});
// Users app
app.use(us.Users.users);
http.createServer(app).listen(app.get('port'), () => {
console.log('Express server listening on port ' + app.get('port'));
});
Right now, the problem is this, I am using mongoose to store some data, and I have mongodb started. Here is what the Users.ts file looks like:
/// <reference path='../d.ts/DefinitelyTyped/node/node.d.ts' />
/// <reference path='../d.ts/DefinitelyTyped/express/express.d.ts' />
/// <reference path='../d.ts/DefinitelyTyped/mongoose/mongoose.d.ts' />
import express = require("express");
import mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/SimpleBlog");
export module Users {
// Exporting information about the user class
export var users: Express = express();
export var base_URL: string = "/users";
// Making Schemas
var UserSchema = new mongoose.Schema({
email: String,
name: String,
age: Number
});
// Attaining users
var db_Users = mongoose.model('Users', UserSchema);
var list;
db_Users.find({}, (err, docs) => {
list = docs;
console.log(docs);
});
// Route for base url
users.get(base_URL, (req, res) => {
res.render("Users/index", {
title: "User List",
user_list: list
});
});
// Route for POST request
users.post(base_URL + "/add", (req, res) => {
try {
console.log(req.body['name']);
new UserSchema({
name: req.body['name'],
email: req.body['email'],
age: req.body['age']
}).save(function (err, docs) {
if (err) { console.log(err); }
});
} catch (Exception) {
console.log(Exception);
}
res.redirect(base_URL);
});
users.get(base_URL + "/add", (req, res) => {
res.render("Users/add", {});
});
}
I get [TypeError: object is not a function] as the error, when I try to save.
The users/add simple gives the user a registration form, and this is done in a jade file. I can also attest that it is not a problem with express.bodyParser() since console.log(req.body['name']); prints out the name of the post request correctly.
Any help regarding this would be helpful.
Your syntax isn't correct for Mongoose.
Regarding this line:
// Attaining users
var db_Users = mongoose.model('Users', UserSchema);
That line returns a Model function/constructor. You'll use that result to create instances of a User. Given all of the Users/UserSchema/User namespace you've got right now, it's a little confusing, so I'll switch it:
// Attaining users
var UserModel = mongoose.model('User', UserSchema);
It looks like the class represents a User, not Users.
When you want to create an instance of a User, you'd create an instance of the UserModel class rather than the schema:
new UserModel({
name: req.body['name'],
email: req.body['email'],
age: req.body['age']
}).save(function (err, docs) {
if (err) { console.log(err); }
});
I did read manuals about access to current user via everyauth. It's say, that I can read current user info from: req.user on my server, everyauth.user and user on my views, but they are undefined. But if I'm try get access from, for example, everyauth.twitter or everyauth.facebook, I'm get user info from this social networks.
I'm want, when get user from database (find or create by social data) it's must save in session variable, like currentUser, and i can get it in helpers and in other databare requests.
My app.js code:
var express = require('express')
, everyauth = require('everyauth')
, Promise = everyauth.Promise
, util = require('util')
, mongoose = require('mongoose')
, routes = require('./routes')
, _ = require('underscore')
mongoose.connect('mongodb://127.0.0.1/base');
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
// Everyauth settings above that app.configure
everyauth.twitter
.consumerKey('secretKey')
.consumerSecret('secret')
.findOrCreateUser(function (session, accessToken, accessTokenSecret, twitterUserData){
var promise = this.Promise();
User.findOrCreateByUidAndNetwork(twitterUserData.id, 'twitter', twitterUserData, promise);
return promise;
})
.redirectPath('/')
everyauth.facebook
.appId("secretId")
.appSecret("secret")
.findOrCreateUser( function (session, accessToken, accessTokenExtra, fbUserMetadata) {
var promise = this.Promise();
User.findOrCreateByUidAndNetwork(fbUserMetadata.id, 'facebook', fbUserMetadata, promise);
return promise;
})
.redirectPath('/');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({secret:'blablabla'}));
app.use(everyauth.middleware()); // Yes, i'm use it
app.use(express.methodOverride());
app.use(app.router); // And it
app.use(express['static'](__dirname + '/public'));
});
everyauth.helpExpress(app); // And this above that routes
app.dynamicHelpers({
currentUser: function (req, res){
return req.user; //it's empty!
}
})
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', routes.index);
require("./controllers/user");
app.listen(80);
And user Scheme:
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
var UserSchema = new Schema({
"uid":{type:String},
"name":{type:String},
"network":{type:String},
"profile":{}
});
mongoose.model('User', UserSchema);
var User = mongoose.model('User');
And user find or create function:
this.findOrCreateByUidAndNetwork = function(uid, network, profile, promise) {
User.find({uid: uid, network: network}, function(err, users) {
if(err) throw err;
if(users.length > 0) {
promise.fulfill(users[0]);// <-- what i want:)
} else {
var user = new User();
user.network = network;
user.uid = uid;
user.profile = profile;
user.name = profile.first_name || profile.name;
user.save(function(err) {
if (err) throw err;
promise.fulfill(user);
});
}
});
};
Thanks, for watching my question. Best regards, Asci
Possibly a little late, but for anyone who needs an answer to this -
On Everyauth's Github page it specifies that "To access the user, configure everyauth.everymodule.findUserById". So for example (again quoting bnoguchi) -
everyauth.everymodule
.findUserById( function (id, callback) {
yourApi.fetchUserById(id, function (err, user) {
if (err) return callback(err);
callback(null, user);
});
// or more succinctly, if your api sends a user to the callback with function signature function (err, user):
// yourApi.fetchUserById(id, callback);
});