d
ESLint与代码检查
我们通常希望对存储在应用程序数据库中的数据应用一些约束。我们的应用程序不应接受缺少或空的content属性的笔记。在路由处理器中检查笔记的有效性:
app.post('/api/notes', (request, response) => {
const body = request.body
if (body.content === undefined) { return response.status(400).json({ error: 'content missing' }) }
// ...
})
如果笔记没有content属性,我们将以400 bad request的状态码响应请求。
在数据存储到数据库之前验证数据格式的一种更智能的方法是使用Mongoose提供的验证功能。
我们可以为模式中的每个字段定义特定的验证规则:
const noteSchema = new mongoose.Schema({
content: { type: String, minLength: 5, required: true }, important: Boolean
})
现在,content字段要求至少为五个字符长,并且被设置为必需,意味着它不能缺失。我们没有对important字段添加任何约束,所以它在模式中的定义没有改变。
minLength和required验证器是Mongoose提供的内置验证器。如果没有一个内置的验证器能满足我们的需求,Mongoose的自定义验证器功能允许我们创建新的验证器。
如果我们试图在数据库中存储一个违反了某些约束的对象,操作将会抛出异常。让我们改变我们创建新笔记的处理器,使其将任何可能的异常传递给错误处理中间件:
app.post('/api/notes', (request, response, next) => { const body = request.body
const note = new Note({
content: body.content,
important: body.important || false,
})
note.save()
.then(savedNote => {
response.json(savedNote)
})
.catch(error => next(error))})
让我们扩展错误处理器以处理这些验证错误:
const errorHandler = (error, request, response, next) => {
console.error(error.message)
if (error.name === 'CastError') {
return response.status(400).send({ error: 'malformatted id' })
} else if (error.name === 'ValidationError') { return response.status(400).json({ error: error.message }) }
next(error)
}
当对象验证失败时,我们从Mongoose返回以下默认错误消息:
我们注意到后端现在有一个问题:在编辑笔记时没有进行验证。 这个问题可以解决,update-validators 文档解释说,在执行findOneAndUpdate和相关方法时,默认不会运行验证。
但是要修复这个问题很简单。让我们也稍微改写一下路由代码:
app.put('/api/notes/:id', (request, response, next) => {
const { content, important } = request.body
Note.findByIdAndUpdate(
request.params.id,
{ content, important }, { new: true, runValidators: true, context: 'query' } )
.then(updatedNote => {
response.json(updatedNote)
})
.catch(error => next(error))
})
Deploying the database backend to production
该应用程序应该能在Fly.io/Render上按原样工作。由于到目前为止我们只对后端进行了修改,所以我们不需要生成前端的新生产构建。
在dotenv中定义的环境变量只会在后端不处于生产模式时使用,即在Fly.io或Render中。
对于生产环境,我们需要在托管我们应用的服务中设置数据库URL。
在Fly.io中,可以通过fly secrets set命令来完成:
fly secrets set MONGODB_URI='mongodb+srv://fullstack:thepasswordishere@cluster0.o1opl.mongodb.net/noteApp?retryWrites=true&w=majority'
当应用正在开发过程中,很可能会出现一些失败的情况。例如,当我第一次部署带有数据库的应用时,一个笔记都没有看到:
浏览器控制台的网络标签页显示,获取笔记的请求并未成功,请求只是在pending状态下停留了很长时间,直到最后以502状态码失败。
浏览器控制台必须始终保持打开状态!
同时,持续关注服务器日志也非常重要。当我打开 fly logs 查看日志时,问题就显而易见了:
数据库URL是 undefined ,所以忘记了执行 fly secrets set MONGODB_URI 命令。
在使用Render时,可以通过在仪表板中定义适当的环境变量来提供数据库URL:
Render仪表板显示服务器日志:
你可以在此GitHub仓库的part3-6分支中找到我们当前应用的完整代码。
Lint
在我们进入下一部分之前,我们介绍一个重要的工具,叫做lint。维基百科对lint的描述如下:
一般来说,lint或者linter是任何检测和标记编程语言中错误的工具,包括样式错误。术语 lint-like behavior 有时用于标记可疑语言使用的过程。Lint类 的工具通常对源代码进行静态分析。
在编译的静态类型语言如Java中,像NetBeans这样的IDE可以指出代码中的错误,甚至是编译错误之外的错误。像checkstyle这样的用于执行静态分析的附加工具,可以用来扩展IDE的能力,也可以指出与样式相关的问题,如缩进。
在JavaScript领域,目前主导的静态分析(又名"linting")工具是ESlint。
让我们使用以下命令将ESlint作为开发依赖项安装到notes后端项目中:
npm install eslint --save-dev
之后我们可以用以下命令初始化一个默认的ESlint配置:
npx eslint --init
我们要回答所有的问题:
配置将会保存在 .eslintrc.js 文件中。我们将在 env 配置中将 browser 改为 node:
module.exports = {
"env": {
"commonjs": true,
"es2021": true,
"node": true },
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parserOptions": {
"ecmaVersion": "latest"
},
"rules": {
}
}
让我们稍微修改一下配置。安装一个插件,该插件定义了一套与代码风格相关的规则:
npm install --save-dev @stylistic/eslint-plugin-js
启用插件并添加一个扩展定义和四个代码风格规则:
module.exports = {
// ...
'plugins': [
'@stylistic/js'
],
'extends': 'eslint:recommended',
'rules': {
'@stylistic/js/indent': [
'error',
2
],
'@stylistic/js/linebreak-style': [
'error',
'unix'
],
'@stylistic/js/quotes': [
'error',
'single'
],
'@stylistic/js/semi': [
'error',
'never'
],
}
}
扩展 eslint:recommended 将一套推荐的规则添加到项目中。此外,还添加了关于缩进、换行、连字符和分号的规则。这四条规则都在Eslint样式插件中定义了。
可以使用以下命令检查和验证像 index.js 这样的文件:
npx eslint index.js
我们建议为linting创建一个单独的 npm script:
{
// ...
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
// ...
"lint": "eslint ." },
// ...
}
现在,npm run lint 命令将检查项目中的每个文件。
当运行命令时,dist 目录中的文件也会被检查,我们不希望这种情况发生、我们可以通过在项目的根目录中创建一个.eslintignore 文件来实现这一点,文件的内容如下:
dist
这将导致整个dist目录不被ESlint检查。
Lint对我们的代码有很多意见:
我们暂时不去修复这些问题。
从命令行执行linter的更好替代方案是将eslint-plugin配置到编辑器中,这将连续运行linter。通过使用插件,你将立即在代码中看到错误。你可以在这里找到更多关于Visual Studio ESLint插件的信息。
VS Code的ESlint插件会用红线下划出风格违规:
这使得错误很容易被发现并立即修复。
ESlint有大量的规则,这些规则通过编辑 .eslintrc.js 文件就可以很容易地使用。
让我们添加eqeqeq规则,如果用非三等号运算符检查等式,它会发出警告。该规则是在配置文件的rules字段下添加的。
{
// ...
'rules': {
// ...
'eqeqeq': 'error',
},
}
在我们进行这项工作的同时,让我们对规则进行一些其他更改。
让我们阻止行尾的不必要的尾随空格,要求大括号前后始终有一个空格,并且也要求箭头函数的函数参数中一致使用空格。
{
// ...
'rules': {
// ...
'eqeqeq': 'error',
'no-trailing-spaces': 'error',
'object-curly-spacing': [
'error', 'always'
],
'arrow-spacing': [
'error', { 'before': true, 'after': true }
]
},
}
我们的默认配置从eslint:recommended中使用了一堆预定的规则:
'extends': 'eslint:recommended',
这包括一个关于 console.log 命令的警告规则。可以通过在配置文件中将其"值"定义为0来禁用一条规则。我们暂时为no-console规则这样做。
{
// ...
'rules': {
// ...
'eqeqeq': 'error',
'no-trailing-spaces': 'error',
'object-curly-spacing': [
'error', 'always'
],
'arrow-spacing': [
'error', { 'before': true, 'after': true }
],
'no-console': 0 },
}
注意 当你对.eslintrc.js文件进行更改时,建议从命令行运行linter。这将验证配置文件是否正确格式化:
如果你的配置文件中有什么错误,lint插件可能会表现得相当不稳定。
许多公司定义编码标准,这些标准通过ESlint配置文件在整个组织中强制执行。不建议反复重新发明轮子,采用别人项目中的现成配置可能是个好主意。最近,许多项目通过采用Airbnb的ESlint配置,采纳了Airbnb的Javascript风格指南。
你可以在 part3-7 分支的这个GitHub仓库中找到我们当前应用程序的全部代码。