NestJS 最先在 2017.1 月立項,2017.5 發佈第一個正式版本,它是一個基於 Express,使用 TypeScript 開發的後端框架。設計之初,主要用來解決開發 Node.js 應用時的架構問題,靈感來源於 Angular。在本文中,我將粗略介紹 NestJS 中的一些亮點。html
NestJS 採用組件容器的方式,每一個組件與其餘組件解耦,當一個組件依賴於另外一組件時,須要指定節點的依賴關係才能使用:git
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { OtherModule } from '../OtherModule';
@Module({
imports: [OtherModule],
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
複製代碼
與 Angular 類似,同是使用依賴注入的設計模式開發github
當使用某個對象時,DI 容器已經幫你建立,無需手動實例化,來達到解耦目的:typescript
// 建立一個服務
@Inject()
export class TestService {
public find() {
return 'hello world';
}
}
// 建立一個 controller
@Controller()
export class TestController {
controller(
private readonly testService: TestService
) {}
@Get()
public findInfo() {
return this.testService.find()
}
}
複製代碼
爲了能讓 TestController
使用 TestService
服務,只須要在建立 module 時,做爲 provider 寫入便可:express
@Module({
controllers: [TestController],
providers: [TestService],
})
export class TestModule {}
複製代碼
固然,你能夠把任意一個帶 @Inject()
的類,注入到 module 中,供此 module 的 Controller 或者 Service 使用。json
背後的實現基於 Decorator + Reflect Metadata,詳情能夠查看 深刻理解 TypeScript - Reflect Metadata。後端
在使用 Express 時,咱們會使用各類各樣的中間件,譬如日誌服務、超時攔截,權限驗證等。在 NestJS 中,Middleware 功能被劃分爲 Middleware、Filters、Pipes、Grards、Interceptors。設計模式
例如使用 Filters,來捕獲處理應用中拋出的錯誤:架構
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
// 一些其餘作的事情,如使用日誌
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
複製代碼
使用 interceptor,攔截 response 數據,使得返回數據格式是 { data: T }
的形式:app
import { Injectable, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface Response<T> {
data: T;
}
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
call$: Observable<T>,
): Observable<Response<T>> {
return call$.pipe(map(data => ({ data })));
}
}
複製代碼
使用 Guards,當不具備 'admin' 角色時,返回 401:
import { ReflectMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);
@Post()
@Roles('admin')
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
複製代碼
得益於 class-validator 與 class-transformer 對傳入參數的驗證變的很是簡單:
// 建立 Dto
export class ContentDto {
@IsString()
text: string
}
@Controller()
export class TestController {
controller(
private readonly testService: TestService
) {}
@Get()
public findInfo(
@Param() param: ContentDto // 使用
) {
return this.testService.find()
}
}
複製代碼
當所傳入參數 text 不是 string 時,會出現 400 的錯誤。
GraphQL 由 facebook 開發,被認爲是革命性的 API 工具,由於它可讓客戶端在請求中指定但願獲得的數據,而不像傳統的 REST 那樣只能在後端預約義。
NestJS 對 Apollo server 進行了一層包裝,使得能在 NestJS 中更方便使用。
在 Express 中使用 Apollo server 時:
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
// Construct a schema, using GraphQL schema language
const typeDefs = gql` type Query { hello: String } `;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.applyMiddleware({ app });
const port = 4000;
app.listen({ port }, () =>
console.log(`Server ready at http://localhost:${port}${server.graphqlPath}`),
);
複製代碼
在 NestJS 中使用它:
// test.graphql
type Query {
hello: string;
}
// test.resolver.ts
@Resolver()
export class {
@Query()
public hello() {
return 'Hello wolrd';
}
}
複製代碼
使用 Decorator 的方式,看起來也更 TypeScript
。
除上述一些列舉外,NestJS 實現微服務開發、配合 TypeORM、以及 Prisma 等特色,在這裏就不展開了。