nest.js從入門到放棄

官方文檔 https://docs.nestjs.com

一、概述
Nest是一個用于構(gòu)建高效,可擴展的Node.js服務(wù)器端應(yīng)用程序的框架。它使用漸進式JavaScript,使用TypeScript構(gòu)建(保留與純JavaScript的兼容性),并結(jié)合了OOP(面向?qū)ο缶幊蹋?,F(xiàn)P(功能編程)和FRP(功能反應(yīng)編程)的元素。

二、NEST-CLI
nest.js 提供了 nest-cli 腳手架,方便快速新建新項目。
使用 nest-cli 構(gòu)建基礎(chǔ)項目:

$ npm i -g @nestjs/cli
$ nest new project-name

新建項目之后:

$ cd project
$ npm install
$ npm run start

三、先決條件
請確保您的操作系統(tǒng)上安裝了 node.js(> = 8.9.0)。

四、基礎(chǔ)項目分析

SRC
  app.controller.ts
  app.module.ts
  main.ts

main.ts 應(yīng)用程序的條目文件。它用于NestFactory創(chuàng)建Nest應(yīng)用程序?qū)嵗?br> app.module.ts 定義AppModule應(yīng)用程序的根模塊。
app.controller.ts 具有單一路線的基本控制器樣本。

import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(ApplicationModule);
  await app.listen(3000);
}
bootstrap();

要創(chuàng)建Nest應(yīng)用程序?qū)嵗?,我們正在使?code>NestFactory。NestFactory它是最基礎(chǔ)的類之一,它公開了一些允許創(chuàng)建應(yīng)用程序?qū)嵗撵o態(tài)方法。該create()方法返回一個實現(xiàn)INestApplication接口的對象,并提供一組可用的方法。

五、運行

npm run start

六、控制器(controller)
控制器負(fù)責(zé)處理傳入的請求并將響應(yīng)返回給客戶端。
控制器的目的是接收應(yīng)用程序的特定請求。在路由該控制器接收用于請求機構(gòu)的控制。通常,每個控制器具有多個路由,并且不同的路由可以執(zhí)行不同的動作。

為了創(chuàng)建一個基本的控制器,我們使用類和裝飾器。裝飾器將類與所需的元數(shù)據(jù)相關(guān)聯(lián),并使Nest能夠創(chuàng)建路由映射(將請求綁定到相應(yīng)的控制器)。

在下面的示例中,我們將使用定義基本控制器所需的 @Controller()裝飾器。我們將指定一個可選的前綴。在Controller裝飾器中使用前綴允許我們避免在路徑可能共享公共前綴時重復(fù)自己。

cats.controller.ts

import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll() {
    return 'This action returns all cats';
  }
}

可以使用CLI提供的快捷命令創(chuàng)建控制器:

$ nest g controller cats

所述@Get()的前裝飾findAll()方法告訴NEST創(chuàng)建此特定路線路徑的端點并映射到該處理程序的每個相應(yīng)的請求。由于我們已經(jīng)為每個route(cats)聲明了一個前綴,因此Nest會將每個/catsGET請求映射到此方法。

請求對象

許多端點需要訪問客戶端請求詳細(xì)信息。實際上,Nest使用特定于庫(默認(rèn)情況下為express)的請求對象。因此,我們可以強制Nest使用@Req()裝飾器將請求對象注入到處理程序中。

cats.controller.ts

import { Controller, Get, Req } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(@Req() request) {
    return 'This action returns all cats';
  }
}

可以使用專用的裝飾器,例如@Body()or @Query(),它們是開箱即用的。

下面展示了nest裝飾器對象express中對象的對應(yīng)關(guān)系

nest裝飾器 express 對象
@Request() req
@Response() res
@Next() next
@Session() req.session
@Param(param?: string) req.params / req.params[param]
@Body(param?: string) req.body / req.body[param]
@Query(param?: string) req.query / req.query[param]
@Headers(param?: string) req.headers / req.headers[param]

新增一個post接口:

cats.controller.ts

import { Controller, Get, Post } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Post()
  create() {
    return 'This action adds a new cat';
  }

  @Get()
  findAll() {
    return 'This action returns all cats';
  }
}

路由通配符

@Get('ab*cd')
findAll() {
  return 'This route uses a wildcard';
}

上述路線路徑匹配abcd,ab_cd,abecd,等等。

狀態(tài)碼
默認(rèn)情況下,響應(yīng)狀態(tài)代碼始終為200,但POST請求為201。我們可以通過@HttpCode(...)在處理程序級別添加裝飾器來輕松更改此行為。


要指定自定義響應(yīng)標(biāo)頭,您可以使用 @Header()裝飾器或特定于庫的響應(yīng)對象。

路徑參數(shù)
需要接受動態(tài)數(shù)據(jù)作為URL的一部分時,具有靜態(tài)路徑的路由無濟于事。為了定義帶參數(shù)的路徑,我們可以直接在路徑路徑中特定路由參數(shù)

@Get(':id')
findOne(@Param() params) {
  console.log(params.id);
  return `This action returns a #${params.id} cat`;
}

async await
每個異步函數(shù)都必須返回一個Promise。這意味著您可以返回Nest能夠自行解決的延遲值。

@Get()
async findAll(): Promise<any[]> {
  return [];
}

七、服務(wù)(service)
創(chuàng)建一個簡單的CatsService provider開始。

cats.service.ts JS

import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: Cat) {
    this.cats.push(cat);
  }

  findAll(): Cat[] {
    return this.cats;
  }
}

nest-cli提供的快捷命令:$ nest g service cats/cats

然后就可以把service引入到controller中使用

cats.controller.ts

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}

依賴注入

Nest是圍繞通常稱為依賴注入的強大設(shè)計模式構(gòu)建的。

在Nest中,由于TypeScript功能,它非常容易管理依賴項,因為它們只是按類型解析,然后傳遞給控制器??的構(gòu)造函數(shù):

constructor(private readonly catsService: CatsService) {}

之后將新建的cat servicecat controller引入app module

app.module.ts

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class ApplicationModule {}

八、模塊(module)
模塊是用@Module()裝飾器注釋的類。的@Module()裝飾提供了元數(shù)據(jù)

module示例

每個應(yīng)用程序至少有一個模塊,一個根模塊。根模塊是Nest開始安排應(yīng)用程序樹的地方。實際上,根模塊可能是應(yīng)用程序中唯一的模塊,尤其是當(dāng)應(yīng)用程序很小的時候。然而,對于大型應(yīng)用程序,它沒有意義。在大多數(shù)情況下,您將擁有多個模塊,每個模塊都具有密切相關(guān)的功能集。

所述@Module()裝飾采用單個對象,其屬性描述該模塊:

providers 將由Nest注入器實例化的提供程序,并且至少可以在此模塊之間共享。
controllers 必須創(chuàng)建的控制器集
imports 導(dǎo)出此模塊中所需的提供程序的導(dǎo)入模塊列表
exports 其子集providers由此模塊提供,并應(yīng)在其他模塊中可用

上一節(jié)中CatsControllerCatsService屬于同一應(yīng)用程序域。我們將考慮將它們移動到一個特征模塊,即CatsModule。

cats/ cats.module.ts

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

nest-cli提供的快捷命令:$ nest g module cats

我們定義了cats.module.ts文件,然后將與此模塊相關(guān)的所有內(nèi)容移動到cats目錄中。我們需要做的最后一件事是將此模塊導(dǎo)入根模塊ApplicationModule。

app.module.ts

import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class ApplicationModule {}

模塊重新導(dǎo)出

@Module({
  imports: [CommonModule],
  exports: [CommonModule],
})
export class CoreModule {}

全局模塊

import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Global()
@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService]
})
export class CatsModule {}

全局模塊只能注冊一次,注冊之后,無需再次引用便可使用。

九、中間件

十、異常處理

。
。

N、數(shù)據(jù)庫
Nest附帶了隨時可用的@nestjs/typeorm軟件包TypeORM,官方說絕對是迄今為止最成熟的對象關(guān)系映射器(ORM)
安裝依賴 $ npm install --save typeorm mysql
新建database文件夾
新建batabase.providers.ts

database.providers.ts

import { createConnection } from 'typeorm';

export const databaseProviders = [
  {
    provide: 'DbConnectionToken',
    useFactory: async () => await createConnection({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [
          __dirname + '/../**/*.entity{.ts,.js}',
      ],
      synchronize: true,
    }),
  },
];

新建database.module.ts

database.module.ts

import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}

存儲庫模式
新建photo文件夾
新建photo.entity.ts

photo/ photo.entity.ts

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Photo {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 500 })
  name: string;

  @Column('text')
  description: string;

  @Column()
  filename: string;

  @Column('int')
  views: number;

  @Column()
  isPublished: boolean;
}

新建photo.providers.ts

photo.providers.ts

import { Connection, Repository } from 'typeorm';
import { Photo } from './photo.entity';

export const photoProviders = [
  {
    provide: 'PhotoRepositoryToken',
    useFactory: (connection: Connection) => connection.getRepository(Photo),
    inject: ['DbConnectionToken'],
  },
];

現(xiàn)在,我們可以注入PhotoRepository的到PhotoService用的@Inject()裝飾:
新建photo.service.ts

photo.service.ts

import { Injectable, Inject } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Photo } from './photo.entity';

@Injectable()
export class PhotoService {
  constructor(
    @Inject('PhotoRepositoryToken')
    private readonly photoRepository: Repository<Photo>,
  ) {}

  async findAll(): Promise<Photo[]> {
    return await this.photoRepository.find();
  }
}

新建photo.module.ts

photo.module.ts

import { Module } from '@nestjs/common';
import { DatabaseModule } from '../database/database.module';
import { photoProviders } from './photo.providers';
import { PhotoService } from './photo.service';

@Module({
  imports: [DatabaseModule],
  providers: [
    ...photoProviders,
    PhotoService,
  ],
})
export class PhotoModule {}

最后導(dǎo)入根模塊app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsModule } from './cats/cats.module'
import { PhotoModule } from './photo/photo.module'
@Module({
  imports: [CatsModule,PhotoModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容