L.Leverage Learn从第一行代码,到读懂真实后端查看项目源码

NestJS 后端开发 / 第 10 课

从类和模块开始写第一个 Nest 应用

先读懂类、方法、构造函数和模块导入,再启动一个真实 NestJS 服务。

◷ 预计 25 分钟 · 面向初学者

上一课用 Express 把请求交给一个函数处理。NestJS 也运行在 Node.js 上,但它用类和模块把后端拆成清楚的部分。先别急着背框架名词:我们先补齐读代码需要的 JavaScript,再运行一个最小应用。课程配套的基础示例项目可下载,它与网站源码分开,是可独立安装、运行和测试的小项目,不是 Leverage 后端源码摘录。

1. 先认识类、方法和 this

对象可以把相关数据放在一起;类则像一份创建同类对象的说明。类里面的函数叫方法,方法中的 this 指向当前对象。

class Greeter {
  constructor(name) {
    this.name = name;
  }
  sayHello() {
    return `你好,${this.name}!`;
  }
}
const greeter = new Greeter('小林');
console.log(greeter.sayHello());

constructor 是创建对象时自动运行的特殊方法。new Greeter('小林') 创建对象并把参数交给构造函数;this.name = name 把参数存到这个对象上。之后调用 greeter.sayHello(),方法通过 this.name 读到同一份数据。Nest 用类描述应用部件,因此理解这几行就能读懂后面的控制器和服务。

2. import 与 export

文件可以导出自己定义的类,再由别的文件导入。Nest 示例使用 TypeScript,但导入导出的作用与 JavaScript 模块相同:一个文件负责定义,另一个文件引用它。

// notes.service.ts
export class NotesService {}
// notes.controller.ts
import { NotesService } from './notes.service.js';

export 让类能被其他文件使用;import 指明从哪里取得它。Node 的模块路径通常需要写明文件扩展名;这个示例用 TypeScript 的 NodeNext 配置,编译后由 Node 执行 JavaScript。

3. 创建并启动 Nest 应用

需要 Node.js 22 或更新版本及 npm。把示例包解压后,在终端进入 nest-basics 文件夹,运行 npm install 安装依赖、npm run build 编译,再运行 npm start。也可以自己按 Nest 官方方式创建项目;本例固定使用 NestJS 11,依赖都只安装在示例目录中。终端显示服务监听地址后,在浏览器访问 http://127.0.0.1:3000/notes,会得到空数组。按 Ctrl+C 停止服务。

入口 src/main.ts 调用 src/bootstrap.ts 导出的 createApp() 创建应用,再用 app.listen(...) 开始监听。把创建过程单独放在 bootstrap.ts,测试就能启动临时服务,而不用执行带永久监听的入口文件。Nest 应用不是只有一个路由函数:它先读取模块的组织,再根据请求调用相应控制器。

4. Module 与应用边界

AppModule 是根模块。模块用 @Module(...) 声明控制器和服务,Nest 从它开始建立应用。controllers 放接收请求的类;providers 放可供 Nest 创建并提供的类。装饰器是贴在类或方法前的特殊标记,让 Nest 读取这些声明。

@Module({
  controllers: [NotesController],
  providers: [NotesService],
})
export class AppModule {}

bootstrap.ts 中的 NestFactory.create(AppModule) 从根模块建起应用。现在无需理解装饰器内部如何实现,只要先记住:模块把相关部件登记到一起。编译时,TypeScript 检查源代码并生成 Node 能运行的 JavaScript;npm run build 负责编译,npm start 执行编译结果。修改源文件后先重新编译,运行中的 Node 不会自动理解未编译的 TypeScript。一个类本身只是结构描述;NestFactory 才负责把模块声明变成运行中的应用。下一课会解释控制器为什么能拿到 NotesService,以及 Nest 怎样创建、复用这个服务。

自己检查

下面哪一段是创建对象,哪一段从文件导入类?new Greeter('小林') 和 import { NotesService } from './notes.service.js'。

答案:new 创建对象;import 从模块取得导出的类。运行起来后试试 GET /notes,再读 src/main.ts 与 src/app.module.ts,把“入口启动”和“模块登记”分开理解。

互动练习:从类到 Nest 启动

先实现被注入的 ReportsService,再写入依赖它的 ReportsController;两者交给 Nest 模块管理,AppModule 引入功能模块后启动监听。按实际依赖顺序排列。

  1. bootstrap(AppModule),调用 listen
  2. AppModule imports ReportsModule
  3. 在 ReportsModule 注册 controller 与 provider
  4. 实现注入 ReportsService 的 ReportsController
  5. 实现 @Injectable() ReportsService

用 ↑ ↓ 调整顺序,再检查答案。也可以用 Tab 和回车操作。

✓
这一课,你已经能……

Nest 应用从 main.ts 启动;模块组织控制器和提供者,类与构造函数是读懂 Nest 写法的基础。