跳到主要内容

NestJS-开始编码

从这里开始,后面的代码默认都是基于Express平台的,如果考虑到性能而采用Fastify那么其中的部分代码可能无效。

首先创建项目

在开始编码之前我们需要创建一个项目

$ yarn globale add @nestjs/cli // 确保已经安装NestJS脚手架
$ nest new nest-first
$ // 1、选择包管理工具

等待包安装完成后,就可以用编辑器打开并开始编码工作了。

启动项目

$ cd nest-first
$ yarn start:dev // 或者: npm run start:dev

第一个接口

修改src目录下的app.controller.ts

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}

@Get()
getHello(): string {
return this.appService.getHello();
}

@Get("first-api")
firstApi() {
return "My first api."
}

}

在浏览器中访问:http://localhost:3000/first-api 得到输出 My first api.

Restful接口

使用下面的命令创建一个新的controller

$ nest g co book

然后使用脚手架工具创建service

$ nest g s book

完成后会在src目结构:

├─app.controller.spec.ts ├─app.controller.ts ├─app.module.ts ├─app.service.ts ├─main.ts ├─book | ├─book.controller.spec.ts | ├─book.controller.ts | ├─book.service.spec.ts | └─book.service.ts

完成后的完整代码请移步Github查看。

项目配置

NestJS有自己配套的配置方案@nestjs/config,不过需要额外安装

yarn add @nestjs/config

接着修改app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config/dist';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BookController } from './book/book.controller';
import { BookService } from './book/book.service';

@Module({
imports: [ConfigModule.forRoot()],
controllers: [AppController, BookController],
providers: [AppService, BookService],
})
export class AppModule {}

然后再在项目根目录创建文件.env,并写入配置

APP_NAME="My First Nest App"

这个时候就可以在需要的地方引入ConfigService,并使用配置信息。

使用配置

导入到provider中

修改app.service.ts

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AppService {
constructor(private readonly configService: ConfigService) {}

getHello(): string {
return this.configService.get<string>('APP_NAME');
}
}

访问 https://localhost:3000 得到 My First Nest App

main.ts中使用

这里以修改端口为例:

首先在.env中加入新的一行

PORT=3002

再修改文件src/main.ts

import { ConfigService } from '@nestjs/config/dist';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
const port = configService.get<string>('PORT');
await app.listen(port || 3001);
}
bootstrap();

此时服务端口已经修改为3002,服务访问地址为: http://localhost:3002

使用MongoDB

数据总归还是需要持久化的,这里选择使用MongoDB最为数据库

NestJS有配套资源@nestjs/mongoose,使用mongoose操作MongoDB

$ yarn add @nestjs/mongoose mongoose

修改文件

// @@filename src/book/book.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type BookDocument = Book & Document;

@Schema()
export class Book {
@Prop()
_id: string

@Prop()
name: string

@Prop()
price: string
}

export const BookSchema = SchemaFactory.createForClass(Book);


// @@filename src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config/dist';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BookController } from './book/book.controller';
import { Book, BookSchema } from './book/book.schema';
import { BookService } from './book/book.service';

@Module({
imports: [
ConfigModule.forRoot(),
MongooseModule.forRootAsync({
inject: [ConfigService],
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
uri: configService.get<string>('MONGO_URL'),
}),
}),
MongooseModule.forFeature([{ name: Book.name, schema: BookSchema }]),
],
controllers: [AppController, BookController],
providers: [AppService, BookService],
})
export class AppModule {}
//

// @@filename book.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { Book, BookDocument } from './book.schema';
import { randomUUID } from 'crypto';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';

@Injectable()
export class BookService {
private readonly books: Array<Book>;

constructor(@InjectModel(Book.name) private bookModel: Model<BookDocument>) {
this.books = [];
}

createBook({ name, price }: Omit<Book, 'id'>) {
return this.bookModel.create({
_id: randomUUID(),
name,
price
});
}

editBook(id: string, { name, price }: Omit<Book, 'id'>) {
return this.bookModel.findByIdAndUpdate(id, { $set: { name, price } })
}

deleteBook(id: string) {
return this.bookModel.findByIdAndDelete(id);
}

listBooks() {
return this.bookModel.find();
}

findBook(id: string) {
return this.bookModel.findById(id);
}
}

修改配置

在.env文件中加入配置:MONGO_URL=MongoDB链接字符串

MONGO_URL="mongodb://localhost:27017/nest-first"

测试

通过Post请求向 http://localhost:3002/book提交数据

$ curl -d "name=第一本书&price=6" -X post http://localhost:3002/book

然后访问:http://localhost:3002/book就可以看到刚刚添加的书了。

完整代码: Github

使用Redis

个人通常喜欢使用IORedis来使用Redis

$ yarn add ioredis

然后在src目录下新建一个redis.service.ts

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Redis } from 'ioredis';

@Injectable()
export class RedisService extends Redis {
constructor(private readonly configService: ConfigService) {
const url = configService.get<string>("REDIS_URL");
const db = +configService.get<number>("REDIS_DB", 0);
super(url, { db });
}
}

app.module.ts中添加此provider

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config/dist';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BookController } from './book/book.controller';
import { Book, BookSchema } from './book/book.schema';
import { BookService } from './book/book.service';
import { RedisService } from './redis.service';

@Module({
imports: [
ConfigModule.forRoot(),
MongooseModule.forRootAsync({
inject: [ConfigService],
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
uri: configService.get<string>('MONGO_URL'),
}),
}),
MongooseModule.forFeature([{ name: Book.name, schema: BookSchema }]),
],
controllers: [AppController, BookController],
providers: [AppService, BookService, RedisService],
})
export class AppModule {}

controller中添加测试运行代码后就可以使用了,最终代码:Github

OpenAPI

OpenAPI规范是一种语言无关的定义格式,用于描述RESTful APIs。Nest提供了一个专门的模块,允许通过利用装饰器生成这样的规范。

$ yarn add @nestjs/swagger swagger-ui-express

修改main.ts中的bootstrap方法,加入如下代码

const config = new DocumentBuilder()
.setTitle('Book example')
.setDescription('The books API description')
.setVersion('1.0')
.addTag('books')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);

访问地址:API即可查看已有的接口

最后

一个简单的、完整的API服务已经全部完成。