使用Express和Mongoose构建Web应用程序的样板应用程序。
$ git clone https://github.com/wikiyodo/expressjs-boilerplate.git
$ cd expressjs-boilerplate
$ npm install
$ cp .env.example .env
$ npm run start:staging
├── /.data/
├── /app/
│ ├── Http
│ │ ├── Controllers
│ │ ├── Middleware
│ ├── Model
├── /bootstrap/
│ │ ├── boot-configuration.js
│ │ ├── boot-environment.js
│ │ ├── boot-helper-path.js
│ │ ├── boot-router.js
│ │ ├── index.js
│ │ ├── post-index.js
├── /commands/
│ ├── index.js
│ ├── seed.js
├── /database/
│ ├── /schema/
│ │ ├── bank.js
│ │ ├── users.js
│ ├── /seeds/
│ │ ├── bank.js
│ ├── /connection.js
│ └── /all-seeds.js
├── /global/
│ ├── constants.js
│ ├── user-roles.js
├── /helpers/ *
├── /resources/
│ ├── /lang/
│ ├── /view/
├── /routes/
│ ├── /api/
│ │ ├── index.js
│ │ ├── user.js
│ │ ├── guest.js
│ ├── index.js
│ ├── routes-string.js
├── /tests/
├── .env
├── .env.example
├── .gitignore
├── app.js
├── cmd.js
├── package.json
├── package-lock.json
└── Readme.md
解析器包含一个可以在各个方面提供帮助的模块列表。
// how to access the resolver
var resolver = require(process.env.resolver);
用于解析路线字符串和物体
resolver.parser(urlSelector, urlParameters, skipBackSlash);
返回相对于根目录的路径字符串。
resolver.router('database/all-seeds'); // returns __ROOT_DIRECTORY__/database/all-seeds
返回到DB连接模块的路径。
const resolver = require(process.env.resolver);
var mongoose = require(resolver.connection());
mongoose.model('User', UserSchema);
将路径返回到传递的模型文件作为参数
const resolver = require(process.env.resolver);
var bankModelPath = pathResolver.model('bank');
const Bank = require(bankModelPath);
返回以参数传递的数据库架构文件的路径
const resolver = require(process.env.resolver);
var bankSchemaPath = resolver.dbSchema('bank');
const BankSchema = require(bankSchemaPath);
var Bank = mongoose.model('Bank', BankSchema);
将路径返回到传递的控制器文件作为参数
const resolver = require(process.env.resolver);
var userControllerPath = resolver.controllers('user-controller');
const UserController= require(userControllerPath);
UserController.deleteUser(user_id, (err, response)=>{ });
返回以参数传递的中间软件文件的路径
const resolver = require(process.env.resolver);
var authMiddlewarePath= resolver.middleware('auth');
const AuthMiddleware= require(authMiddlewarePath);
app.use('/user', AuthMiddleware);
所有路线都包含在project_directory /途径中,并将 /映射到基本路由器,该路由器包含在 /routes/index.js中
var express = require('express');
var router = express.Router();
// this contains all API routes.
var apiRouter = require('./api/index');
// this contains all routes that can be accessed via the web browsers
var webRouter = require('./web/index');
var routeString = require('./routes-string');
module.exports = (app) => {
app.use('/api', apiRouter);
app.use('/', apiRouter);
};
假设您要创建一个API端点,以便人们在单独的文件中获取当前服务器时间(Time.js,它将包含与时间有关的所有端点)。
创建并打开/routes/api/time.js。那么内容应该看起来像:
var express = require('express');
var router = express.Router();
// endpoint = /api/time/current
router.get('/current'), (req, res)=>{
res.status = 200;
res.send({time:Date.now});
res.end();
});
module.exports = router;
...
const TimeRouter = require('./time'); // this loads the time.js file
...
// use endpoint = /api/time
router.use('/time', TimeRouter );
动态路由使您可以将所有路由/路径声明在文件中,并致电它们在任何地方使用,而无需重新删除它。一旦改变了路线的值,它就会在任何地方更改。
所有路线和路径都放在 /routes/Routes-string.js中
const api = {
user: {
get: '/:id',
roles: {
get: '/all',
},
register: {
':role': {
save: '/save/:userId?'
}
}
},
bank: {
get: '/all'
}
};
const WEB = {
};
module.exports = {
api,
...WEB
};
...
const resolver = require(process.env.resolver);
// the dynamic routing module is place in the resolver and can be accessed resolver.parser
var $ = resolver.parser;
...
// $('api.bank.get', 'api') returns /api/bank/all as path
router.get($('api.bank.get', 'api'), BankController.getAllBanks);
resolver.parser(路径,trimindex)用于解析路线的索引。
Given that our route is -->
{
user: {
get:{
all: '/all'
},
':userId':{
profile: 'profile'
}
}
}
// to formulate user/get/all we will transverse through the index user.get.all
// to formulate user/:userId/profile, transverse through user.:userId.profile
resolver.parser('user.get.all'); // returns /user/get/all
resolver.parser('user.get.all', 'user'); // returns /get/all
resolver.parser('user.get.all', 'user.get'); // returns /all
resolver.parser('user.:userId.profile', {
userId: 3
}); // returns /user/3/profile
要设置您的数据库详细信息,请打开 /.env文件,并如下更新内容:
"DATABASE": {
"USERNAME": "YOUR DATABASE USERNAME",
"PASSWORD": "YOUR DATABASE PASSWORD",
"HOST": "YOUR DATABASE HOST e.g localhost",
"PORT": "YOUR DATABASE PORT e.g 27017",
"NAME": "YOUR DATABASE NAME",
"OPTIONS": {} // extra mongoose options
}
您不得希望使用Controller对象将所有请求处理逻辑定义为封闭逻辑,而是希望组织此行为。控制器可以将相关请求分组为单个对象(来源:https://laravel.com/docs/5.7/controllers)。要创建一个控制器,请在/app/http/Controller中创建一个新文件,例如用户controller.js。典型的控制器看起来像这样。
const resolver = require(process.env.resolver);
const Controller = require('./controller');
var UserController = {};
UserController.getUserRoles = (req, res, next) => {
var returnableRoles = [];
for (var role in Roles)
returnableRoles.push(Roles[role]);
Controller.defaultResponse(res, returnableRoles);
};
module.exports = UserController;
要在任何地方访问您的控制器,您可以轻松地使用Resolver.controllers(“您的controller的名称”)
...
const resolver = require(process.env.resolver);
const UserController = require(resolver.controllers('user-controller'));
...
router.get('/user/roles', UserController.getUserRoles);
...
中间件提供了一种方便的机制,用于过滤HTTP请求输入您的应用程序。 MiddleWares存储在/App/http/中间件中以创建中间件,创建一个新的文件,例如/app/http/中间软件。典型的中间件看起来像这样。
module.exports = (req, res, next) => {
// your logic here
// proceed to next middleware
next();
}
要在任何地方访问中间件,您可以轻松地使用Resolver.middleware(“您的名字中间件”)
...
const resolver = require(process.env.resolver);
const AuthMiddleware= require(resolver.middleware('auth'));
...
router.use('/user', AuthMiddleware);
...
该项目的所有数据库架构都放置在 /数据库 /模式目录中。典型的模式看起来像这样:
const resolver = require(process.env.resolver);
var mongoose = require(resolver.connection());
var lastUpdateDate = require('./plugins/last-update');
var Schema = mongoose.Schema;
// sample for a bank schema
var structure = {};
structure.name = String;
structure.code = String;
var bankSchema = new Schema(structure);
bankSchema.plugin(lastUpdateDate);
module.exports = bankSchema;
该样板包括一种使用种子文件将数据库播种的简单方法。所有数据库种子都放在 /数据库 /种子目录中。
const pathResolver = require(process.env.resolver);
const Bank= require(pathResolver.model('bank')).Bank;
var getBanks = () => {
return {
"ACCESS BANK": "044",
"ACCESSMOBILE": "323",
"ASO SAVINGS AND LOANS": "401",
"CELLULANT": "317",
"CENTRAL BANK OF NIGERIA": "001",
"CITIBANK": "023",
"CORONATION MERCHANT BANK": "559",
"CORPORETTI": "310",
"COVENANT MICROFINANCE BANK": "551",
"DIAMOND BANK": "063",
"EARTHOLEUM(QIK QIK)": "302",
"ECOBANK NIGERIA": "050",
"ECOMOBILE": "307",
"EKONDO MICROFINANCE BANK": "562",
"ENTERPRISE BANK": "084",
"EQUITORIAL TRUST BANK": "040",
"E - TRANZACT": "306",
"FBN M- MONEY": "309",
"FBN MORTGAGES": "413",
"FETS(MY WALLET)": "314",
"FIDELITY BANK": "070",
"FIDELITY MOBILE": "318",
"FINATRUST MICROFINANCE BANK": "608",
"FIRST BANK OF NIGERIA": "011",
"FIRST CITY MONUMENT BANK": "214",
"FIRST INLAND BANK": "085",
"FORTIS MICROFINANCE BANK": "501",
"FORTIS MOBILE": "308",
"FSDH": "601",
"GT MOBILE MONEY": "315",
"GUARANTY TRUST BANK": "058",
"HEDONMARK": "324",
"HERITAGE BANK": "030",
"IMPERIAL HOMES MORTGAGE BANK": "415",
"INTERCONTINENTAL BANK": "069",
"JAIZ BANK": "301",
"JUBILEE LIFE": "402",
"KEGOW": "303",
"KEYSTONE BANK": "082",
"MAINSTREET BANK": "014",
"MIMONEY(POWERED BY INTELLIFIN)": "330",
"M - KUDI": "313",
"MONETIZE": "312",
"MONEYBOX": "325",
"NEW PRUDENTIAL BANK": "561",
"NPF MFB": "552",
"OCEANIC BANK": "056",
"OMOLUABI SAVINGS AND LOANS": "606",
"ONE FINANCE": "565",
"PAGA": "327",
"PAGE MFBANK": "560",
"PARALLEX": "502",
"PARKWAY(READY CASH)": "311",
"PAYATTITUDE ONLINE": "329",
"PAYCOM": "304",
"PROVIDUS BANK": "101",
"SAFETRUST MORTGAGE BANK": "403",
"SEED CAPITAL MICROFINANCE BANK": "609",
"SKYE BANK": "076",
"STANBIC IBTC BANK": "221",
"STANBIC MOBILE": "304",
"STANDARD CHARTERED BANK": "068",
"STERLING BANK": "232",
"STERLING MOBILE": "326",
"SUNTRUST": "100",
"TEASY MOBILE": "319",
"TRUSTBOND": "523",
"U - MO": "316",
"UNION BANK OF NIGERIA": "032",
"UNITED BANK FOR AFRICA": "033",
"UNITY BANK": "215",
"VFD MICROFINANCE BANK": "566",
"VISUAL ICT": "328",
"VTNETWORK": "320",
"WEMA BANK": "035",
"ZENITH BANK": "057",
"ZENITH MOBILE": "322"
};
};
var locationSeed = () => {
// get all banks
banks = getBanks();
var insertables = [];
for (var name in banks) {
var code = banks[name];
insertables.push({
name,
code
});
}
Bank.insertMany(insertables, (err, docs) => {
if (err) {
console.error(err);
}
});
};
module.exports = locationSeed;
将种子放在种子目录中后,您必须在 /database/all-seeds.js中指定它,以使播种机能够找到它
var SeedBanks= require('./seeds/banks');
var exports = {
SeedBanks,
// place your seeds here
};
module.exports = exports;
要迁移您的种子,然后使用Bellow命令。
> node cmd run:seed
这使您可以在CLI(命令行接口)中运行某些命令。
创建自定义命令;创建一个将逻辑托管到您的命令/命令中的文件
var exports = {};
exports.removeOldUsers = (args) => {
// logic here
};
module.exports = exports;
然后在/commands/index.js中指定您的命令名称和可呼叫函数
var seeder = require('./seed');
/**
* @info all arguments are to be placed here
*/
const arguments = {
'run:seed': seeder.runSeed,
'your_command': CallableFunction
};
module.exports = arguments;
这使您可以根据某些规则验证给定值。
// Use this to import validation module
var resolver = require(process.env.resolver);
var validator = require(resolver.validator());
验证是不同步的。验证器(array_of_rules,回调);
validator([
{
fieldName: "name", // name of the field
fieldValue: 2, // the value of the field
validation: 'min:3|max:4', // set of validation rules
errorMessage:"Invalid name" // custom error message for all rules.
}
], (result) => {
res.send(result);
res.end();
});
允许的规则包括:
这检查给出值是指定值的最小长度或值。例如,最小值:2,检查字符串的最小长度为2个字符,如果它是数字的,则检查给定数字是否大于或等于2。
这检查给出值是指定值的最大长度或值。例如,最小值:2,检查字符串的最大长度为2个字符,如果它是数字的,则检查给定的数字是否小于或等于2。
这检查给定值仅包含字母字符,而没有其他内容。
这检查给定值仅包含alpha数值字符,而没有其他内容。
这确认给定值是一组项目。
这确认给定值是小数号
这证明了给定值是有效的电子邮件。
这验证了给定值仅包含数值值。
这检查给定值是否是有效的电话号码。
这检查给定值不是空的。
检查验证是否失败
validator(rules, (result) => {
result.failed(); // returns a boolean. true when it fails and false when it doesnt.
result.getFirst('field name'); // returns the first error for the field and undefined in case there is no error
result.getError('field name'); // returns all errors for the field
});
单位测试尚未包含在此样板中。但是,您可以选择自己包含它。
欢迎任何人和所有人做出贡献。
麻省理工学院