功能实现:
- 用户登入、用户登出
- 用户/文章分类/文章 各个模块 列出列表+分页列表+增删改查
架构层面 演示:
- egg-swagger-doc-feat
- 根据jsdoc生成路由,swagger+jsdoc调试开发
- egg-validate
- 根据contract模型校验
ctx.validate(ctx.rule.xxx)
- 添加自定义类型
ObjectId
工程模块层面 演示:
- egg-jwt
ctx.app.jwt.sign({ data, exp }, ctx.app.config.jwt.secret)
- egg-mongoose
- 操作数据库
ctx.model
- mongoose-autopopulate
- egg-cors
- 允许跨域(安全问题依照具体项目来优化)
api运用层面 演示:
- egg-bcrypt
- 混淆密码 对比密码
ctx.genHash
ctx.compare
以上
this.ctx
简写为ctx
。
演示了:
- 抽象公共的 success response
- 错误处理中间件拦截error,并记录错误日志
- AppHooks: 在根目录创建app.js
- 自动更新createdAt和updatedAt时间戳
- 封装 获取分页 和 获取列表 接口
- 用
id
代替_id
返回给client - 变量名不要包含
delete
,免得解构到了哪一层和js关键字delete
重名 - 接入EasyMock
- 401
- 用户名或密码错误
- 404
- 根据id去找该条记录,不存在
- 409
- 该用户名已被注册
- 此分类名已存在
- 422
- 报文的格式有问题
- 调用egg-validate插件校验不通过
- 校验密码格式;校验邮箱格式
- 修改密码或者重置密码没有独立出接口出来
- 目前用的是“子文档”来实现文档的嵌套,看看效果怎么样
- fields字段查询列表要优化一下,正则的效果不太行。比如搜“测试”,只输入“测”搜不出来。
- 如果操作的项在一条记录的某个字段下,findByIdAndUpdate没法只返回当前操作的项
- bug:npm start下,首次模拟create category时,该操作返回的ObjectId是错误的
各种
Model.find**
和Model.find**And**
方法被归类为Queries方法,Queries方法执行后返回的是Query对象
(而不是Promise)。 参考通俗的解释
我想实现的需求是,执行Model.find**
之后,如果find找不到对应的document,就去执行我定义的错误回调中的ctx.throw(404, '该文章不存在')
。
执行ctx.throw(404, '该文章不存在')
是为了抛出一个错误提示给前端,前端再按照约定在页面上展示给用户,用户就会看到类似“该文章不存在”这样的友好提示。
可以直接用不太优雅的代码来实现:
async myUpdate(payload) {
const { ctx } = this
const { id } = payload;
const doc = await this.findById(id)
if (!doc) {
ctx.throw(404, cantFindText)
}
return this.findByIdAndUpdate(id, payload)
}
以上代码实现了需求。但是其实执行了2次find
;并且每次都要判断if (!doc)
导致代码很多。
orFail接口在后续的新Mongoose版本中出现了以后,可以这样简单封装:
(像myUpdate这个service一样,其他service取而代之每次调用findByIdAndUpdateOrFail就不用加错误提示代码,清爽多了)
async myUpdate(payload) {
const { id } = payload;
return this.findByIdAndUpdateOrFail(id, payload)
}
async findByIdAndUpdateOrFail(...args) {
return this.ctx.model[User].findByIdAndUpdate(...args)
.orFail(() => this.ctx.throw(404, cantFindText));
}
这个简单的封装:find方法后接.orFail
有一个弊端就是:orFail
被定位为用于一个查询语句的末端,所以没办法再后接.populate
等方法,例如:
const pointer = this.ctx.model['Article'].findByIdAndUpdate(id, payload);
pointer.populate('commentList.commenter').orFail(/*...*/) // 这样可以
pointer.orFail(/*...*/).populate('commentList.commenter') // 这样不行
# 已安装:
npm i await-stream-ready stream-wormhole image-downloader -s
为了提高安全性,/config/config.default.js
的某些字段由config/secret-constant.js
文件提供,而这个文件需要你自己创建并且设置对应字段(下面是设置的示例):
exports.mongooseUrl = 'mongodb://127.0.0.1:27017/example_cms_name';
exports.jwtSecret = 'anything';
exports.appInfoKeySalt = 'anything';
$ npm i
$ npm run dev
$ open http://localhost:7009/
http://127.0.0.1:7009/swagger-ui.html
http://localhost:7009/public/index.html
$ npm start
$ npm stop
- Use
npm run lint
to check code style. - Use
npm test
to run unit test. - Use
npm run autod
to auto detect dependencies upgrade, see autod for more detail.
node ≥ 14