NestJS 服務簡介
服務
在企業應用中,我們遵循 SOLID 原則,其中 S 代表 Single Responsibility。
控制器負責接受來自客戶端的 HTTP 請求並提供響應。為了提供響應,您可能需要連接到一些外部數據源。
如果我們在內部添加連接外部源的代碼,我們就沒有遵循單一責任原則。
為避免此問題,您使用服務,該服務將負責提供一些數據,這些數據可以在整個應用程序中重複使用。它還可以保存一些驗證邏輯或驗證用戶的邏輯。
創建和使用服務
在 NestJS 中可以創建兩種類型的服務:
- 基於類的提供者
- 非基於類的提供者
注意:如果你來自 Angular,你很有可能已經知道這些概念。
基於類的提供者
要創建基於類的提供程序,我們可以使用下面的 CLI 命令,該命令將在產品文件夾中創建服務。
nest generate service product
在產品文件夾中,你會發現兩個文件:
product.service.ts
(為了邏輯。)product.service.spec.ts
(用於單元測試。)
您最終可能會為一項功能使用多種服務,甚至可能使用多種類型的提供商。
使用基於類的提供者
現在打開 product.service.ts
文件並添加以下代碼,我們將從 ProductController
中移動一些代碼 到 ProductService
.
import { Injectable } from '@nestjs/common';
@Injectable()
export class ProductService {
products = [
{ id: 1, name: 'One Plus 7', price: 48000 },
{ id: 2, name: 'I Phone X', price: 64999 }
];
getProducts() {
return this.products;
}
addProduct(product:any){
this.products.push(product);
}
getProductById(id:number) {
return this.products.find(p => p.id === id);
}
}
現在服務已經準備好了,打開 product.controller.ts
並進行以下更改。
import { ProductService } from './product.service';
@Controller('product')
export class ProductController {
constructor(private productService: ProductService) {}
@Get()
GetProducts() {
return this.productService.getProducts();
}
@Post()
AddProduct(@Req() req: Request, @Res() res: Response) {
this.productService.addProduct(req.body);
// return json data with default status code
return res.json({ id: req.body.id });
// to update the status code
//return res.status(205).json({ id: req.body.id})
}
@Get(':id')
GetProductById(@Param() param: any) {
return this.productService.getProductById(+param.id);
}
}
這裡使用 ProductService 的方式稱為依賴注入。
與 Controller 一樣,Services 也需要註冊,CLI 為我們完成了這項工作,您可以通過將其添加到模塊的 providers 數組中手動完成。
providers: [AppService, ProductService]
我們將在接下來的文章中介紹更多關於基於類的服務。
非基於類的提供者
我們還可以創建一個不是基於類的服務的服務。有兩種:
- 令牌:我們可以使用字符串值作為令牌。
- 工廠:當我們的服務需要來自其他服務的一些數據時很有用。
創建令牌
您可以創建一個注入令牌用作服務,為此,創建一個新文件 product.token.ts
在產品文件夾中並添加以下代碼:
export interface Product {
endPoint: string;
}
export const PRODUCT = 'PRODUCT';
export const Product_Token : Product = {
endPoint: 'http://localhost:3000/product'
}
現在打開 app.module.ts
並使用 providers 屬性註冊令牌。
import { PRODUCT, Product_Token } from './product/product.token';
providers: [
{
provide : PRODUCT,
useValue: Product_Token
}]
接下來,打開product.service.ts
讓我們使用這個令牌並添加以下代碼。這僅用於演示目的,在實時應用程序中我們可能希望使用此值。
import { Injectable, Inject } from '@nestjs/common';
import { PRODUCT, Product } from './product.token';
constructor(@Inject(PRODUCT) product: Product)
{
console.log(product.endPoint);
}
使用值運行應用程序後,endPoint
將登錄到控制台。
使用工廠
工廠是另一種類型的提供者,可用於非常特殊的用例。
一般我們提供服務的時候,在模塊加載的時候就解決了,但是也有可能需要動態創建實例的實例,這就是我們需要工廠的地方。
例如,獲取數據庫連接,讓客戶端在運行時決定連接哪個數據庫。
運行以下命令來創建兩個服務:
nest generate service dbprovider
nest generate service client
在 client.service.ts
中添加以下代碼 .
import { Injectable } from '@nestjs/common';
@Injectable()
export class ClientService {
getClientDetails() {
return {
client: 'test',
db: 'databaseconnection'
}
}
}
接下來,打開 dbprovider.service.ts
並添加以下代碼。
import { Injectable } from '@nestjs/common';
@Injectable()
export class DbproviderService {
constructor(private connection: string) { }
getProductsForClient() {
return this.connection;
}
}
在 dbprovider.service.ts
,這裡我們使用的是字符串屬性,如果你嘗試運行這個應用程序,你會得到錯誤,因為這是不允許的。
我們要創建 DbproviderService
的實例 在運行時,所以我們需要再做一個改變。打開app.module.ts
並刪除 DbproviderService
來自 providers
屬性。
NestJS 讓我們創建工廠,創建一個新文件 connection.provider.ts
,並添加以下代碼。
import { ClientService } from "./client/client.service";
import { DbproviderService } from "./dbprovider/dbprovider.service";
export const dbConnectionFactory = {
provide: 'ClientConnection',
useFactory : (clientSerice: ClientService) => {
return new DbproviderService(clientSerice.getClientDetails().db);
},
inject: [ClientService]
}
在這裡,我們正在創建一個 DbproviderService
的新實例 通過獲取 db
從 ClientService
.您可以在這裡使用多個服務,您只需在 useFactory
中以逗號分隔傳遞它們 並且需要在inject
中添加相同的服務 屬性。
現在我們完成了工廠,讓我們註冊並使用它。打開app.module.ts
並添加 dbConnectionFactory
在 providers
屬性。
接下來,打開 product.service.ts
並添加以下代碼。
constructor(@Inject(PRODUCT) product: Product,
@Inject('ClientConnection') dbProviderService: DbproviderService){
console.log(product.endPoint);
console.log(dbProviderService.getProductsForClient())
}
結論
我們學習瞭如何在 NestJS 中創建和使用不同類型的提供程序,我們使用依賴注入設計模式來使用服務,這也可以讓您實現單一職責。
服務是單例的,但我們也可以控制Services的範圍,我們會在下一篇文章中看到。