基于Restify的REST API目录结构与样板代码咨询
我完全懂你这种感受——找个能直接复用、结构清晰的Restify样板确实不容易,毕竟大部分教程都停留在小demo层面。下面我分享一套我在实际项目里常用的结构,还有导入处理的最佳实践,应该能帮你理清思路:
一、推荐的Restify项目目录结构
这套结构遵循职责单一原则,把不同功能的代码拆分到对应目录,后期维护和扩展都很方便:
your-api/ ├── src/ │ ├── config/ # 配置文件(数据库、环境变量、端口等) │ │ ├── index.js │ │ └── env/ │ │ ├── development.js │ │ └── production.js │ ├── controllers/ # 业务逻辑处理(对应每个资源的CRUD) │ │ ├── user.controller.js │ │ └── order.controller.js │ ├── routes/ # 路由定义,把请求映射到控制器 │ │ ├── index.js │ │ ├── user.routes.js │ │ └── order.routes.js │ ├── models/ # 数据模型(搭配ORM如Sequelize/Mongoose使用) │ │ ├── User.js │ │ └── Order.js │ ├── middlewares/ # 自定义中间件(权限验证、日志、错误处理等) │ │ ├── auth.middleware.js │ │ └── error-handler.middleware.js │ ├── services/ # 复用性业务服务(邮件发送、第三方API调用等) │ │ ├── email.service.js │ │ └── payment.service.js │ ├── utils/ # 通用工具函数(格式化、验证、常量定义) │ │ ├── validation.utils.js │ │ └── constants.js │ └── server.js # 服务器入口,初始化Restify、加载路由和中间件 ├── package.json ├── .env # 环境变量(不要提交到Git) └── .gitignore
简单解释下各目录的作用:
config/:集中管理不同环境的配置,比如开发环境用本地数据库,生产环境用云数据库controllers/:直接处理请求和响应,调用services完成业务逻辑,不直接操作数据库routes/:只负责定义URL和HTTP方法,把请求转发给对应的控制器方法middlewares/:处理请求前后的通用逻辑,比如验证用户登录状态、记录请求日志services/:抽离可复用的业务逻辑,比如发送验证码、生成订单,让控制器更简洁
二、导入处理的最佳实践
Restify默认支持CommonJS,但现在很多项目也会用ES Modules,两种方案的处理方式如下:
1. 使用CommonJS(Restify默认)
如果你的项目用require()和module.exports,可以通过模块别名解决相对路径过长的问题:
- 安装
module-alias包:npm install module-alias - 在
package.json里添加别名配置:"_moduleAliases": { "@config": "./src/config", "@controllers": "./src/controllers", "@routes": "./src/routes" } - 在
server.js顶部注册别名:require('module-alias/register');
之后就可以这样导入,不用再写冗长的../:
const config = require('@config'); const userController = require('@controllers/user.controller');
2. 使用ES Modules(现代方式)
如果想改用import/export,先在package.json里设置"type": "module",然后:
- 导入路径必须加
.js后缀(比如import { getUser } from '../controllers/user.controller.js') - 同样可以用别名,在
package.json里配置:"imports": { "#config/*": "./src/config/*", "#controllers/*": "./src/controllers/*" }
之后导入就会更简洁:
import config from '#config/index.js'; import { getUser } from '#controllers/user.controller.js';
三、快速启动的核心代码示例
基于上面的结构,你可以快速写出基础的启动代码:
server.js(服务器入口):const restify = require('restify'); const routes = require('./routes'); const errorHandler = require('./middlewares/error-handler.middleware'); const server = restify.createServer({ name: 'your-api', version: '1.0.0' }); // 注册Restify自带的通用中间件 server.use(restify.plugins.acceptParser(server.acceptable)); server.use(restify.plugins.queryParser()); server.use(restify.plugins.bodyParser()); // 加载所有路由 routes(server); // 全局错误处理 server.on('restifyError', errorHandler); const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log('%s listening at %s', server.name, server.url); });routes/index.js(统一注册路由):const userRoutes = require('./user.routes'); module.exports = (server) => { userRoutes(server); // 后续添加其他路由,比如orderRoutes(server) };user.routes.js(用户资源路由):const { getUser, createUser } = require('../controllers/user.controller'); module.exports = (server) => { server.get('/users/:id', getUser); server.post('/users', createUser); };
这种结构的好处是职责清晰,每个模块只做一件事,哪怕后期项目变大,也能轻松扩展新的资源或功能。你可以根据自己的项目规模调整,比如小项目可以把services和utils合并,或者不用models(如果直接操作SQL而不用ORM)。
内容的提问来源于stack exchange,提问作者Circle
相关产品推荐
相关产品推荐

