(全文 4000 多字,需要 7 分钟阅读时间)
代码已上传到我的 github 仓库「链接」
使用NodeJS、Express 和 MongoDB 创建 REST API
环境
- NodeJS
- MongoDB
如果你还没有安装,请去官方网站按照文档指南安装。
起步
- NodeJS 应用
- 运行 Express 服务器
- 使用 TypeScript 开发
- 使用 Passport 进行身份验证
- 将数据存储在 MongoDB 数据库中
- 使用 ESLint 和 Prettier 规范代码
- 使用 Morgan 和 Winston 进行日志记录
首先,使用 Typescript 创建一个简单的 Express 服务器,包括代码规范和日志记录。
搭建项目
创建文件夹,使用包管理器初始化项目,在这里我使用了 npm,可能会出现网络问题,你也可以使用 cnpm 或者 yarn
mkdir rest-api-node
cd rest-api-node
npm init -y
将创建项目的 package.json
接下来安装项目依赖:
npm install --save-dev typescript ts-node
ts-node 可以直接在 NodeJS 上执行 TypeScript 脚本
安装所需的其他依赖项:
npm install --save express dotenv
npm install --save-dev @types/dotenv @types/express nodemon
接下来,将项目初始化为 TypeScript 项目。
npx tsc --init
这将创建 tsconfig.json文件,它包含编译项目所需的编译器选项。 使用下面的代码片段替换生成的 tsconfig.json。
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"rootDir": "./",
"outDir": "./build",
}
}
有关编译器选项的更多信息,请参阅官方文档「链接」
前面安装依赖时我们安装了 dotenv,用来管理应用中的环境变量。dotenv 模块从 .env文件中加载变量并将它们转换为 process.env 变量。 使用这个模块,环境变量可以简单地在项目内的任何地方加载 。
创建一个 .env文件在项目的根级别并添加以下环境变量。
PORT=3300
现在我们完成了基本的依赖安装和配置,可以开始编写程序了。创建 src 文件作为根目录
mkdir src
cd src
创建 app.ts 并添加以下代码以启动 Express 服务器。
import * as dotenv from "dotenv";
import express from "express";
const app = express();
dotenv.config();
if (!process.env.PORT) {
process.exit(0);
}
app.listen(process.env.PORT, () => {
console.log(`服务运行在端口:${process.env.PORT}`);
});
更新 package.json
"scripts": {
"build": "tsc --project ./",
"start": "node build/src/app.js"
}
第一个命令是打包 typescript,第二个是运行命令
npm run build
npm run start
更新完代码后每次都要使用命令未免太过麻烦,使用 nodemon 自动重启:
更新 package.json
"start:dev": "nodemon src/app.ts"
通过 nodemon 启动 express 服务器:
npm run start:dev
一旦你通过 nodemon 启动服务, 无需在每次代码更改后重新启动它,因为 nodemon将检测到它们并自动重新启动服务器。
设置 ESLint 和 Prettier
Linter 是帮助开发人员根据一套完善的规则维护代码的工具。 linter 维护两种类型的规则,即代码质量规则和格式规则。 代码质量规则确保代码编写良好,并且可能发生的潜在问题非常少。 格式规则保证代码的格式在整个项目中是相同的。 因此,代码质量规则和格式规则的结合产生了一个 linter。
ESLint 是最受欢迎和维护良好的 Javascript linter 之一。 Prettier 是最流行的 Javascript 格式化程序之一。 尽管 ESLint 包括格式化程序,不过还是建议使用 Prettier 与 ESLint, 以便于私用 ESLint 负责代码质量和 Prettier 负责代码格式
安装 ESLint 和 Prettier
npm install --save-dev eslint @typescript-eslint/eslint-plugin @ typescript-eslint/parser prettier eslint-config-prettier eslint-plugin-prettier
eslint-config-prettier 和 eslint-plugin-prettier 是帮助 Prettier 在 ESLint 环境下运行的模块。确保了相关规则不会冲突。
创建 .eslintrc.json,包含 ESLint 配置
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"prettier",
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"prettier/prettier": "error"
}
}
创建 .eslintignore 文件,设置 linter 不会检查构建的文件。
build
创建 .prettierrc.json 其中包含格式化规则
{
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
}
更新脚本中的 package.json
"lint": "eslint --ext .js,.jsx,.ts ."
执行:
npm run lint
可以看到报错了,错误提示为格式问题,在最后一行按下 enter 键即可,不过我们可以把格式化交给 prettier。
将以下脚本添加到 package.json:
"lint:fix": "eslint --fix --ext .js,.jsx,.ts ."
运行 npm run lint 和 npm run lint:fix 解决 linting 问题,以便代码遵循最佳实践。如果你使用的是VScode,也可以安装 ESLint 和 Prettier 插件。它会在 IDE内部就把错误展示出来。
创建日志记录
日志记录是软件开发中的主要概念之一。 我们应该始终尝试尽可能多地记录应用程序中的活动。 日志记录有助于解决应用程序中的问题并有助于检查过去的活动。 winston是一个很强大的记录器模块,我们将使用 winston 在我们的应用程序中创建记录器。
安装 winston
npm install --save winston
创建 utils 文件夹 在 src 里,然后在该文件夹中创建 logger.ts
import winston from 'winston';
const levels = {
error: 0,
warn: 1,
info: 2,
debug: 3,
};
const folderPath = process.env.LOG_FOLDER || 'logs';
const level = process.env.LOG_LEVEL || 'debug';
const colors = {
error: 'red',
warn: 'yellow',
info: 'green',
debug: 'gray',
};
winston.addColors(colors);
const format = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
winston.format.printf(
(info: winston.Logform.TransformableInfo) =>
`${info.timestamp} [${info.level}] ${info.message}`
)
);
const transports = [
new winston.transports.Console({
format: winston.format.combine(winston.format.colorize({ all: true })),
}),
new winston.transports.File({
filename: `${folderPath}/error.log`,
level: 'error',
}),
new winston.transports.File({ filename: `${folderPath}/app.log` }),
];
const Logger = winston.createLogger({
level: level,
levels,
format,
transports,
});
export default Logger;
我们将使用四种不同的日志级别 debug, info, warn和 error。通过环境变量提供日志文件文件夹。如果没有提供,则提供默认位置。也可以通过环境变量提供记录器应该捕获的最低日志级别,默认级别是 debug。
更新 app.ts 测试日志记录:
import * as dotenv from 'dotenv';
import express from 'express';
import Logger from './utils/logger';
const app = express();
dotenv.config();
if (!process.env.PORT) {
process.exit(0);
}
app.get('/logger', (_, res) => {
Logger.error('error log');
Logger.warn('warn log');
Logger.info('info log');
Logger.debug('debug log');
res.send('Hello world');
});
app.listen(process.env.PORT, () => {
console.log(`服务运行在: ${process.env.PORT}`);
});
重新打包运行服务器后访问:
http://localhost:3300/logger
可以看到记录器的不同级别以不同的颜色查看。 此外,还可以看到一个名为的新文件夹 logs已经创建了两个日志文件 app.log和 error.log。
我们实现了一个记录器,可以在应用程序中使用它来记录应用程序活动。 但 winston无法记录 HTTP 请求,并且由于我们正在运行服务器,因此记录 HTTP 请求和相关数据非常重要。morgan是一个快速中间件模块,可用于监视 HTTP 请求以进行日志记录。
安装依赖:
npm install --save morgan
npm i --save-dev @types/morgan
现在创建记录器中间件。 首先,创建一个文件夹 middlewares 在src里,并在文件夹内创建 logger.middleware.ts文件:
更新 logger.ts 以满足 http:
import winston from 'winston';
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
};
const folderPath = process.env.LOG_FOLDER || 'logs';
const level = process.env.LOG_LEVEL || 'debug';
const colors = {
error: 'red',
warn: 'yellow',
info: 'green',
http: 'blue',
debug: 'gray',
};
winston.addColors(colors);
const format = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
winston.format.printf(
(info: winston.Logform.TransformableInfo) =>
`${info.timestamp} [${info.level === 'http' ? 'api' : info.level}] ${
info.message
}`
)
);
const transports = [
new winston.transports.Console({
format: winston.format.combine(winston.format.colorize({ all: true })),
}),
new winston.transports.File({
filename: `${folderPath}/error.log`,
level: 'error',
}),
new winston.transports.File({ filename: `${folderPath}/app.log` }),
];
const Logger = winston.createLogger({
level: level,
levels,
format,
transports,
});
export default Logger;
更新 app.ts 以使用日志记录作为 Express 服务器中的中间件。
import * as dotenv from 'dotenv';
import express from 'express';
import Logger from './utils/logger';
import loggerMiddleware from './middlewares/logger.middleware';
const app = express();
dotenv.config();
app.use(loggerMiddleware);
if (!process.env.PORT) {
process.exit(0);
}
app.get('/logger', (_, res) => {
Logger.error('error log');
Logger.warn('warn log');
Logger.info('info log');
Logger.http('api log');
Logger.debug('debug log');
res.send('Hello world');
});
app.listen(process.env.PORT, () => {
console.log(`服务运行在: ${process.env.PORT}`);
});
重新打包运行服务器后访问:
http://localhost:3300/logger
所有的 API 请求都会通过 morgan 中间件。
结论
在本文章中,我们成功地运行了一个 Express 服务器,且配置了 ESLint 和 Prettier,以便遵循代码最佳实践。 还设法使用创建了一个记录器 winston 和 morgan 用来捕获和记录应用程序活动以及 HTTP 请求。
接下来将探索如何将 express 服务器与 MongoDB 数据库连接并实现可以执行 CRUD 操作的 API 。
你也可以拉取我的 github 「链接」 代码进行修改,完善。有任何问题请在 github 上提 issue 或者评论区指出。