Node.js & Express - 应用程序结构的全局模块和最佳实践
node.js & express - global modules & best practices for application structure
我正在构建一个节点.js应用程序,它是一个REST api,使用express和mongoose为我的mongodb。我现在已经设置了所有 CRUD 端点,但我只是想知道两件事。
-
如何扩展这种路由方式,具体而言,如何在路由之间共享模块。我希望我的每条路由都进入一个新文件,但显然只有一个数据库连接,正如你所看到的,我已经将猫鼬包含在人们的顶部.js。
我 是否必须在我的人中写出模型的模式 3 次.js?第一个模式定义模型,然后我列出 createPerson 和 updatePerson 函数中的所有变量。这感觉就像我当年制作php/mysql CRUD的方式,哈哈。对于更新函数,我尝试编写一个循环来循环"p"以自动检测要更新的字段,但无济于事。任何提示或建议都会很棒。
另外,我希望对整个应用程序有任何意见,作为节点的新手,很难知道您做某事的方式是最有效或"最佳"的做法。谢谢!
应用.js
// Node Modules
var express = require('express');
app = express();
app.port = 3000;
// Routes
var people = require('./routes/people');
/*
var locations = require('./routes/locations');
var menus = require('./routes/menus');
var products = require('./routes/products');
*/
// Node Configure
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
// Start the server on port 3000
app.listen(app.port);
/*********
ENDPOINTS
*********/
// People
app.get('/people', people.allPeople); // Return all people
app.post('/people', people.createPerson); // Create A Person
app.get('/people/:id', people.personById); // Return person by id
app.put('/people/:id', people.updatePerson); // Update a person by id
app.delete('/people/:id', people.deletePerson); // Delete a person by id
console.log('Server started on port ' + app.port);
人.js
//Database
var mongoose = require("mongoose");
mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/');
// Schema
var Schema = mongoose.Schema;
var Person = new Schema({
first_name: String,
last_name: String,
address: {
unit: Number,
address: String,
zipcode: String,
city: String,
region: String,
country: String
},
image: String,
job_title: String,
created_at: { type: Date, default: Date.now },
active_until: { type: Date, default: null },
hourly_wage: Number,
store_id: Number, // Inheirit store info
employee_number: Number
});
var PersonModel = mongoose.model('Person', Person);
// Return all people
exports.allPeople = function(req, res){
return PersonModel.find(function (err, person) {
if (!err) {
return res.send(person);
} else {
return res.send(err);
}
});
}
// Create A Person
exports.createPerson = function(req, res){
var person = new PersonModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
address: {
unit: req.body.address.unit,
address: req.body.address.address,
zipcode: req.body.address.zipcode,
city: req.body.address.city,
region: req.body.address.region,
country: req.body.address.country
},
image: req.body.image,
job_title: req.body.job_title,
hourly_wage: req.body.hourly_wage,
store_id: req.body.location,
employee_number: req.body.employee_number
});
person.save(function (err) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "Person was not created." });
}
});
return res.send(person);
}
// Return person by id
exports.personById = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "That person doesn't exist." });
}
});
}
// Delete a person by id
exports.deletePerson = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
return person.remove(function (err) {
if (!err) {
return res.send(person.id + " deleted");
} else {
console.log(err);
return res.send(404, { error: "Person was not deleted." });
}
});
});
}
// Update a person by id
exports.updatePerson = function(req, res){
return PersonModel.findById(req.params.id, function(err, p){
if(!p){
return res.send(err)
} else {
p.first_name = req.body.first_name;
p.last_name = req.body.last_name;
p.address.unit = req.body.address.unit;
p.address.address = req.body.address.address;
p.address.zipcode = req.body.address.zipcode;
p.address.city = req.body.address.city;
p.address.region = req.body.address.region;
p.address.country = req.body.address.country;
p.image = req.body.image;
p.job_title = req.body.job_title;
p.hourly_wage = req.body.hourly_wage;
p.store_id = req.body.location;
p.employee_number = req.body.employee_number;
p.save(function(err){
if(!err){
return res.send(p);
} else {
console.log(err);
return res.send(404, { error: "Person was not updated." });
}
});
}
});
}
我在这里采取了另一种方法。不是说它是最好的,但让我解释一下。
- 每个架构(和模型)都位于其自己的文件(模块)中
- 特定 REST 资源的每组路由都位于其自己的文件(模块)中
- 每个路由模块只需
require
它需要的猫鼬模型(仅 1 个) - 主文件(应用程序入口点)只需
require
所有路由模块即可注册它们。 - Mongo 连接位于根文件中,并作为参数传递给需要它的任何内容。
我的应用程序根目录下有两个子文件夹 - routes
和 schemas
.
这种方法的好处是:
- 只需编写一次架构。
- 每个 REST 资源 (CRUD) 的路由注册不会污染主应用文件
- 您只需定义一次数据库连接
以下是特定架构文件的外观:
文件:/schemas/theaterSchema.js
module.exports = function(db) {
return db.model('Theater', TheaterSchema());
}
function TheaterSchema () {
var Schema = require('mongoose').Schema;
return new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
address: { type: String, required: true },
latitude: { type: Number, required: false },
longitude: { type: Number, required: false },
phone: { type: String, required: false }
});
}
以下是特定资源的路由集合的外观:
文件:/路线/剧院.js
module.exports = function (app, options) {
var mongoose = options.mongoose;
var Schema = options.mongoose.Schema;
var db = options.db;
var TheaterModel = require('../schemas/theaterSchema')(db);
app.get('/api/theaters', function (req, res) {
var qSkip = req.query.skip;
var qTake = req.query.take;
var qSort = req.query.sort;
var qFilter = req.query.filter;
return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake)
.exec(function (err, theaters) {
// more code
});
});
app.post('/api/theaters', function (req, res) {
var theater;
theater.save(function (err) {
// more code
});
return res.send(theater);
});
app.get('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.put('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.delete('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
return theater.remove(function (err) {
// more code
});
});
});
};
下面是根应用程序文件,它初始化了连接并注册了所有路由:
文件:应用.js
var application_root = __dirname,
express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
http = require('http');
var app = express();
var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string');
app.configure(function () {
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, "public")));
app.use('/images/tmb', express.static(path.join(application_root, "images/tmb")));
app.use('/images/plays', express.static(path.join(application_root, "images/plays")));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.get('/api', function (req, res) {
res.send('API is running');
});
var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction });
// more code
app.listen(4242);
希望这是有帮助的。
我发现这篇StackOverflow帖子非常有帮助:
Mongoose & NodeJS 项目的文件结构
诀窍是将架构放入models
目录中。 然后,在任何路线中,您都可以require('../models').whatever
.
另外,我通常在app.js中启动猫鼬数据库连接,并且仅在连接启动后启动Express服务器:
mongoose.connect('mongodb://localhost/whateverdb')
mongoose.connection.on('error', function(err) {
console.log("Error while connecting to MongoDB: " + err);
process.exit();
});
mongoose.connection.on('connected', function(err) {
console.log('mongoose is now connected');
// start app here
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
});
>我会 https://github.com/madhums/node-express-mongoose-demo 看看这个项目。这是关于如何以标准方式构建 nodejs 应用程序的一个很好的例子。
- NodeJS:一个全局EventEmitter或每个模块它'他自己的
- 带有全局变量、咖啡脚本和回调的模块 CSV
- 从脚本标记的全局范围调用webpack模块中的函数
- 如何在javascript模块中包含jquery而不与全局名称空间冲突
- webpack在全局范围内执行模块
- 全局安装的NodeJS npm模块不执行节点的主/bin JavaScript文件
- 单元测试使用全局的模块.XMLHttpRequest
- 如何将全局变量放在Globals.js模块中,并在其他模块中访问它们
- 如何在 Node 中访问模块全局变量.js例如浏览器中的 window.variable
- 当作为 CommonJS 模块加载时,Angular 是否全局将自己分配给“window.angular”
- AngularJS需要JS浏览器化和Javascript模块/全局范围的噩梦
- nodejs 中模块中的全局对象是什么
- RequireJS - 全局需求和模块需求之间的差异
- TypeScript:从模块创建全局变量
- 可以在模块中运行.导出访问模块中的全局变量
- 对角度模块使用单个全局变量是否是一种反模式
- 从 Drupal 7 中的模块.js文件调用全局 JS 函数
- 什么被认为是在节点模块中共享“全局”变量的好方法
- Node.js请求模块全局事件
- 使用模块全局作用域定义可从prototype访问的私有类字段