使用 Node.js 构建 Restful CRUD API
目录
CRUD API 是什么意思?
CRUD 范式代表四种原始数据库操作,即CREATE
、、和。READ
UPDATE
DELETE
所以,我们所说的“API”指的CRUD API
是能够从数据库中获取、和实体的 API create
。read
在update
本delete
例中,实体是员工。
让我们开始吧
API 端点如下
方法 | 网址 | 描述 |
---|---|---|
得到 | API/员工 | 获取所有员工 |
得到 | api/员工/id | 获取特定员工 |
邮政 | API/员工 | 创建新员工 |
放 | api/员工/id | 更新现有员工 |
删除 | api/员工/id | 删除现有员工 |
我们创建存储库并安装依赖项。
入口点是 server.js 文件。
mkdir express-api
cd express-api
npm init
npm install express helmet morgan body-parser monk joi dotenv --save
npm install nodemon --save-dev
关于套餐
express:它是一个最小且灵活的 Node.js Web 应用程序框架。helmet
:它有助于保护 express 应用程序中的 HTTP 标头。morgan
:它是 Node 的 HTTP 请求记录器中间件。js
body-parser:它负责解析传入的请求主体。monk
:一个微小的层,为 MongoDB 的使用提供了实质性的可用性改进。joi
:它是一种对象模式描述语言和对象验证器。dotenv
:它从 .env 文件加载环境变量。nodemon
:当检测到目录中的文件更改时,它会自动重新启动节点应用程序。
设置 Express Web 服务器
./src/server.js
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const bodyParser = require('body-parser');
require('dotenv').config();
const app = express();
const monk = require('monk');
app.use(helmet());
app.use(morgan('dev'));
app.use(bodyParser.json());
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
创建并配置 .env 文件
。./.env
包含我们使用的所有环境变量。TEST_DB_URL
变量用于测试用例,以防止测试数据插入数据库。此外,您还可以指定所需的端口号。
DB_URL = localhost/my-employees
TEST_DB_URL = localhost/test-my-employees
PORT = 5000
./src/db/schema.js创建数据模式并定义属性必须遵循的
验证规则。name
job
const Joi = require('joi');
const schema = Joi.object({
name: Joi.string()
.min(3)
.max(30)
.required(),
job: Joi.string()
.min(3)
.max(30)
.required(),
})
module.exports = schema;
./src/db/connection.js
连接数据库
const monk = require('monk');
let dbUrl = process.env.DB_URL;
if (process.env.NODE_ENV === 'test') {
dbUrl = process.env.TEST_DB_URL;
}
const db = monk(dbUrl);
module.exports = db;
./src/middlewares/index.js
创建错误中间件来处理错误并给出正确的响应。
function notFound(req, res, next) {
res.status(404);
const error = new Error('Not Found', req.originalUrl);
next(error);
}
function errorHandler(err, req, res, next){
res.status(res.statusCode || 500);
res.json({
message: err.message,
stack: err.stack
});
}
module.exports = {
notFound,
errorHandler
}
我们导入./src/db/connection.js
,./src/db/schema.js
并将./src/middlewares/index.js
文件放入./src/server.js
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const { notFound, errorHandler } = require('./middlewares');
require('dotenv').config();
const schema = require('./db/schema');
const db = require('./db/connection');
const employees = db.get('employees');
const app = express();
app.use(helmet());
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(notFound);
app.use(errorHandler);
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
现在,我们对 API 端点进行编码
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const { notFound, errorHandler } = require('./middlewares');
require('dotenv').config();
const schema = require('./db/schema');
const db = require('./db/connection');
const employees = db.get('employees');
const app = express();
app.use(helmet());
app.use(morgan('dev'));
app.use(bodyParser.json());
/* Get all employees */
app.get('/', async (req, res, next) => {
try {
const allEmployees = await employees.find({});
res.json(allEmployees);
} catch(error) {
next(error);
}
});
/* Get a specific employee */
app.get('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const employee = await employees.findOne({
_id: id
});
if(!employee) {
const error = new Error('Employee does not exist');
return next(error);
}
res.json(employee);
} catch(error) {
next(error);
}
});
/* Create a new employee */
app.post('/', async (req, res, next) => {
try {
const { name, job } = req.body;
const result = await schema.validateAsync({ name, job });
const employee = await employees.findOne({
name,
})
// Employee already exists
if (employee) {
res.status(409); // conflict error
const error = new Error('Employee already exists');
return next(error);
}
const newuser = await employees.insert({
name,
job,
});
console.log('New employee has been created');
res.status(201).json(newuser);
} catch(error) {
next(error);
}
});
/* Update a specific employee */
app.put('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const { name, job } = req.body;
const result = await schema.validateAsync({ name, job });
const employee = await employees.findOne({
_id: id
});
// Employee does not exist
if(!employee) {
return next();
}
const updatedEmployee = await employees.update({
_id: id,
}, {
$set: result},
{ upsert: true }
);
res.json(updatedEmployee);
} catch(error) {
next(error);
}
});
/* Delete a specific employee */
app.delete('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const employee = await employees.findOne({
_id: id
});
// Employee does not exist
if(!employee) {
return next();
}
await employees.remove({
_id: id
});
res.json({
message: 'Success'
});
} catch(error) {
next(error);
}
});
app.use(notFound);
app.use(errorHandler);
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
我们进入package.json
文件并用以下内容替换脚本部分
"scripts": {
"start": "node src/server.js",
"dev": "nodemon src/server.js"
},
该命令npm start
启动 Node.js 应用程序,该命令npm run dev
启动 Node.js 应用程序,唯一的区别是我们所做的任何更改都将自动由 nodemon 监控。
我们“分割”./src/server.js
并创建./src/app.js
文件。
./src/app.js
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const { notFound, errorHandler } = require('./middlewares');
require('dotenv').config();
const schema = require('./db/schema');
const db = require('./db/connection');
const employees = db.get('employees');
const app = express();
app.use(helmet());
app.use(morgan('dev'));
app.use(bodyParser.json());
/* Get all employees */
app.get('/', async (req, res, next) => {
try {
const allEmployees = await employees.find({});
res.json(allEmployees);
} catch(error) {
next(error);
}
});
/* Get a specific employee */
app.get('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const employee = await employees.findOne({
_id: id
});
if(!employee) {
const error = new Error('Employee does not exist');
return next(error);
}
res.json(employee);
} catch(error) {
next(error);
}
});
/* Create a new employee */
app.post('/', async (req, res, next) => {
try {
const { name, job } = req.body;
const result = await schema.validateAsync({ name, job });
const employee = await employees.findOne({
name,
})
// Employee already exists
if (employee) {
res.status(409); // conflict error
const error = new Error('Employee already exists');
return next(error);
}
const newuser = await employees.insert({
name,
job,
});
console.log('New employee has been created');
res.status(201).json(newuser);
} catch(error) {
next(error);
}
});
/* Update a specific employee */
app.put('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const { name, job } = req.body;
const result = await schema.validateAsync({ name, job });
const employee = await employees.findOne({
_id: id
});
// Employee does not exist
if(!employee) {
return next();
}
const updatedEmployee = await employees.update({
_id: id,
}, {
$set: result},
{ upsert: true }
);
res.json(updatedEmployee);
} catch(error) {
next(error);
}
});
/* Delete a specific employee */
app.delete('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const employee = await employees.findOne({
_id: id
});
// Employee does not exist
if(!employee) {
return next();
}
await employees.remove({
_id: id
});
res.json({
message: 'Success'
});
} catch(error) {
next(error);
}
});
app.use(notFound);
app.use(errorHandler);
module.exports = app;
./src/server.js
const app = require('./app');
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
最后一步是重构我们的代码并创建./src/routes/employees
。
./src/routes/employees.js
const express = require('express');
const schema = require('../db/schema');
const db = require('../db/connection');
const employees = db.get('employees');
const router = express.Router();
/* Get all employees */
router.get('/', async (req, res, next) => {
try {
const allEmployees = await employees.find({});
res.json(allEmployees);
} catch (error) {
next(error);
}
});
/* Get a specific employee */
router.get('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const employee = await employees.findOne({
_id: id,
});
if (!employee) {
const error = new Error('Employee does not exist');
return next(error);
}
res.json(employee);
} catch (error) {
next(error);
}
});
/* Create a new employee */
router.post('/', async (req, res, next) => {
try {
const { name, job } = req.body;
const result = await schema.validateAsync({ name, job });
const employee = await employees.findOne({
name,
});
// Employee already exists
if (employee) {
const error = new Error('Employee already exists');
res.status(409); // conflict error
return next(error);
}
const newuser = await employees.insert({
name,
job,
});
res.status(201).json(newuser);
} catch (error) {
next(error);
}
});
/* Update a specific employee */
router.put('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const { name, job } = req.body;
const result = await schema.validateAsync({ name, job });
const employee = await employees.findOne({
_id: id,
});
// Employee does not exist
if (!employee) {
return next();
}
const updatedEmployee = await employees.update({
_id: id,
}, { $set: result },
{ upsert: true });
res.json(updatedEmployee);
} catch (error) {
next(error);
}
});
/* Delete a specific employee */
router.delete('/:id', async (req, res, next) => {
try {
const { id } = req.params;
const employee = await employees.findOne({
_id: id,
});
// Employee does not exist
if (!employee) {
return next();
}
await employees.remove({
_id: id,
});
res.json({
message: 'Employee has been deleted',
});
} catch (error) {
next(error);
}
});
module.exports = router;
./src/app.js文件如下所示
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const { notFound, errorHandler } = require('./middlewares');
const app = express();
require('dotenv').config();
app.use(helmet());
app.use(morgan('dev'));
app.use(bodyParser.json());
const employees = require('./routes/employees');
app.use('/api/employees', employees);
app.use(notFound);
app.use(errorHandler);
module.exports = app;
您可以在我的 GitHub 存储库express-api中查看整个项目
文章来源:https://dev.to/zagaris/build-a-restful-crud-api-with-node-js-2334