第 168 章:第一个 NestJS 应用
学习目标
- 理解 NestJS 启动流程
- 掌握 main.ts 配置
- 学会添加第一个路由
- 实现简单的数据返回
一、Hello World 进阶版
1.1 创建路由
typescript
// app.controller.ts
import { Controller, Get, Param, Query, Post, Body } from '@nestjs/common';
import { AppService } from './app.service';
@Controller('api')
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('hello')
getHello(): string {
return this.appService.getHello();
}
@Get('hello/:name')
getHelloName(@Param('name') name: string): string {
return this.appService.getHelloName(name);
}
@Get('search')
search(@Query('q') query: string) {
return { query, results: [] };
}
@Post('echo')
echo(@Body() body: any) {
return { received: body };
}
}1.2 测试
bash
# 启动
pnpm run start:dev
# 测试
curl http://localhost:3000/api/hello
# Hello NestJS!
curl http://localhost:3000/api/hello/Tom
# Hello, Tom!
curl "http://localhost:3000/api/search?q=nest"
# {"query":"nest","results":[]}
curl -X POST http://localhost:3000/api/echo \
-H "Content-Type: application/json" \
-d '{"name":"Tom"}'
# {"received":{"name":"Tom"}}二、统一返回格式
typescript
// common/result.ts
export class Result<T> {
code: number;
message: string;
data: T;
timestamp: number = Date.now();
static ok<T>(data: T): Result<T> {
return { code: 200, message: 'OK', data, timestamp: Date.now() };
}
static fail<T = null>(code: number, message: string, data?: T): Result<T> {
return { code, message, data: data as T, timestamp: Date.now() };
}
}typescript
// app.controller.ts
import { Result } from './common/result';
@Get('hello')
getHello(): Result<string> {
return Result.ok(this.appService.getHello());
}三、添加全局前缀
typescript
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api'); // ① 所有路由加 /api 前缀
await app.listen(3000);
}四、跨域配置
bash
pnpm add corstypescript
// main.ts
import cors from 'cors';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: ['http://localhost:5173', 'https://your-domain.com'],
credentials: true,
});
await app.listen(3000);
}五、环境变量
bash
pnpm add @nestjs/configtypescript
// app.module.ts
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // 全局可用
envFilePath: '.env', // 配置文件路径
}),
],
...
})
export class AppModule {}env
# .env
PORT=3000
DATABASE_URL=postgres://user:pass@localhost:5432/db
JWT_SECRET=your-secrettypescript
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = app.get(ConfigService);
await app.listen(config.get('PORT', 3000));
}六、第一个完整示例
typescript
// src/user/user.controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
interface User {
id: number;
name: string;
email: string;
}
@Controller('users')
export class UserController {
private users: User[] = [
{ id: 1, name: 'Tom', email: 'tom@x.com' },
{ id: 2, name: 'Jerry', email: 'jerry@x.com' },
];
@Get()
findAll() {
return { code: 200, data: this.users };
}
@Get(':id')
findOne(@Param('id') id: string) {
const user = this.users.find(u => u.id === Number(id));
if (!user) return { code: 404, message: 'Not found' };
return { code: 200, data: user };
}
@Post()
create(@Body() body: Omit<User, 'id'>) {
const newUser: User = {
id: this.users.length + 1,
...body,
};
this.users.push(newUser);
return { code: 201, data: newUser };
}
}七、热重载与日志
start:dev 模式自动监听文件变化,日志彩色输出。
typescript
// app.service.ts
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class AppService {
private readonly logger = new Logger(AppService.name);
getHello(): string {
this.logger.log('getHello called'); // ① 日志
this.logger.warn('warning');
this.logger.error('error', 'stack');
this.logger.debug('debug');
return 'Hello NestJS!';
}
}八、本章小结
| 概念 | 关键 |
|---|---|
| 启动 | NestFactory.create(AppModule) |
| 路由装饰器 | @Get() @Post() 等 |
| 参数装饰器 | @Param() @Query() @Body() |
| 全局前缀 | app.setGlobalPrefix('api') |
| 跨域 | app.enableCors() |
| 环境变量 | @nestjs/config |
动手练习
- 创建一个
/api/users的 GET 接口,返回 3 个用户 - 添加 POST 接口创建用户
- 添加全局前缀
/api - 用 curl 测试所有接口
推荐阅读
- 📖 Controllers
- 📖 全局配置