gRPC, Nest.js kép méretező
February 7, 2024
February 7, 2024
Ebben a projektben egy egyszerű, mégis hatékony képvágó alkalmazást hozunk létre, amely a NestJS és a gRPC technológiákra épül. A NestJS egy modern, teljes értékű Node.js keretrendszer a szerveroldali alkalmazásokhoz, míg a gRPC egy magas teljesítményű, nyílt forráskódú univerzális RPC keretrendszer, amely lehetővé teszi a szolgáltatások közötti gyors és hatékony kommunikációt.
Telepítjük a nest.js-t
POWERSHELLnpm i -g @nestjs/cli
Ezután hozzuk létre magát a projektet, amely az API szerverünket fogja szolgálni. A projekt létrehozásához használjuk a nest new parancsot, és adjuk meg a projekt nevét, például grpc-picture-resize. Ez a parancs létrehoz egy új mappát a megadott névvel, és inicializál egy új NestJS projektet benne:
POWERSHELLnest new grpc-picture-resize
A képek átméretezésére szolgáló logikát egy külön mikroszolgáltatásban fogjuk implementálni, ami lehetővé teszi számunkra, hogy izoláltan kezeljük ezt a funkcionalitást, és szükség esetén könnyen skálázhatóvá tegyük. Hozzuk létre ezt a mikroszolgáltatást a nest g app parancs segítségével, és adjuk hozzá a projektünkhöz mint egy új alkalmazást. A mikroszolgáltatás neve legyen például resize:
POWERSHELLnest g app resize
A rendszerünk működéséhez még telepítjük a következő könyvtárakat:
POWERSHELLnpm install @nestjs/microservices
POWERSHELLnpm install @grpc/proto-loader @grpc/grpc-js ts-proto
A kép levágáshoz a következő javascript könyvtárat telapítjük
POWERSHELLnpm install sharp
A nest-cli fájl módosítása a monoreponknak megfelelően
JSON//nest-cli.json{"$schema": "https://json.schemastore.org/nest-cli","collection": "@nestjs/schematics","sourceRoot": "apps/grpc-picture-resize/src","compilerOptions": {"deleteOutDir": true,"webpack": true,"tsConfigPath": "apps/grpc-picture-resize/tsconfig.app.json"},"monorepo": true,"root": "apps/grpc-picture-resize","projects": {"grpc-picture-resize": {"type": "application","root": "apps/grpc-picture-resize","entryFile": "src/main","sourceRoot": "./","compilerOptions": {"tsConfigPath": "apps/grpc-picture-resize/tsconfig.app.json","assets": ["proto/*.proto"],"watchAssets": true}},"resize": {"type": "application","root": "apps/resize","entryFile": "src/main","sourceRoot": "./","compilerOptions": {"tsConfigPath": "apps/resize/tsconfig.app.json","assets": ["proto/*.proto"],"watchAssets": true}}}}
A package resize sor definiálja a protobuf üzenetek és szolgáltatások névterét. Ez segít elkerülni a névütközéseket, amikor különböző protobuf definíciókat használunk együtt.
A service ImageResizer blokk definiál egy szolgáltatást, amely tartalmaz egy ResizeImage RPC-t (Remote Procedure Call). Ez az eljárás vár egy ResizeRequest kérést, és egy ResizeResponse választ ad vissza.
ResizeImage RPC: Lehetővé teszi a kliensek számára, hogy képet küldjenek átméretezésre. A kérés tartalmazza a képet mint byte tömböt (bytes image), valamint a kívánt szélességet (int32 width) és magasságot (int32 height).
ResizeRequest: Ez az üzenet tartalmazza a kép átméretezéséhez szükséges adatokat. Az image mező a kép bináris tartalmát tárolja, míg a width és height mezők az új méreteket adják meg.
ResizeResponse: A válaszüzenet, amely tartalmazza az átméretezett kép adatait. A fileName a létrehozott képfájl nevét tartalmazza, míg a resizedWidth és resizedHeight mezők az átméretezett kép szélességét és magasságát adják meg.
PLAIN TEXT//resize.protesyntax = "proto3";package resize;service ImageResizer {rpc ResizeImage (ResizeRequest) returns (ResizeResponse) {}}message ResizeRequest {bytes image = 1;int32 width = 2;int32 height = 3;}message ResizeResponse {string fileName = 1;int32 resizedWidth = 2;int32 resizedHeight = 3;}
A proto fájl elkészítése után protoc-vel typescript fájlt hozunk belőle létre
Windows-nál a következő lépésekkel tudod alkalmazni a protoc-t:
A programuk főkönyvtárából futtatjuk a következő kódot:
POWERSHELLprotoc --plugin=protoc-gen-ts_proto="C:\path\to\your\project\folder\node_modules\.bin\protoc-gen-ts_proto.cmd" --ts_proto_out=./ --ts_proto_opt=nestJs=true ./proto/min.proto
—plugin-nél megadjuk a használt plugint és a helyét
—ts_proto_out-nál megadjuk, hogy nestJs-re optimalizálunk és hogy hova másolunk és hogy hol van a felhasznált proto fájlunk
Az AppController osztályban definiálunk egy POST végpontot ('/resize'), amely lehetővé teszi a felhasználók számára, hogy egy kép URL-jét, valamint a kívánt szélességet és magasságot megadva kérjenek képátméretezést. A metódus letölti a képet a megadott URL-ről, létrehoz egy átméretezési kérést a letöltött képből, majd a resizeImage szolgáltatási hívással átméretezi a képet.
TYPESCRIPT//grpc-picture-resize/src/app.controller.tsimport { Body, Controller, Post } from '@nestjs/common';import { AppService } from './app.service';import fetch from 'node-fetch';@Controller()export class AppController {constructor(private readonly appService: AppService) {}@Post('/resize')async resizeImageByUrl(@Body() body: { imageUrl: string; width: number; height: number },) {// Downloading the image from the provided URLconst response = await fetch(body.imageUrl);if (!response.ok) {throw new Error('Failed to download the image');}const imageBuffer = await response.buffer();// Creating a resize request with the downloaded imageconst resizeRequest = {image: imageBuffer,width: body.width,height: body.height,};// Resizing the image using the gRPC servicereturn this.appService.resizeImage(resizeRequest);}}
Az AppModule fájlban konfiguráljuk a gRPC klienst a ClientsModule.register metódussal. Itt adunk meg egy szolgáltatásnevet ('resize'), amely megegyezik a proto fájlban definiált csomagnévvel, és beállítjuk a kommunikáció módját (Transport.GRPC). A protoPath opcióval megadjuk a gRPC definíciós fájl elérési útját, amely leírja a képek átméretezésére szolgáló interfészt.
TYPESCRIPT//grpc-picture-resize/src/app.module.tsimport { Module } from '@nestjs/common';import { ClientsModule, Transport } from '@nestjs/microservices';import { AppController } from './app.controller';import { AppService } from './app.service';import { join } from 'path';@Module({imports: [ClientsModule.register([{name: 'resize',transport: Transport.GRPC,options: {package: 'resize',protoPath: join(__dirname, '../resize.proto'),},},]),],controllers: [AppController],providers: [AppService],})export class AppModule {}
Az AppService osztály felelős a gRPC szolgáltatás fogyasztásáért. A konstruktorban injektáljuk a gRPC klienst, és az onModuleInit metódusban inicializáljuk a képátméretező kliens-szolgáltatást a getService<ImageResizerClient> hívással. A resizeImage metódus végrehajtja a képátméretezési kérést, és visszaadja az átméretezett kép fájlnevét.
TYPESCRIPT//grpc-picture-resize/src/app.service.tsimport { Inject, Injectable, OnModuleInit } from '@nestjs/common';import { ClientGrpc } from '@nestjs/microservices';import {ResizeRequest,IMAGE_RESIZER_SERVICE_NAME,ImageResizerClient,} from 'proto/resize';@Injectable()export class AppService implements OnModuleInit {private imageResizerClient: ImageResizerClient;constructor(@Inject('resize') private clientGrpc: ClientGrpc) {}onModuleInit() {this.imageResizerClient = this.clientGrpc.getService<ImageResizerClient>(IMAGE_RESIZER_SERVICE_NAME,);}async resizeImage(resizeRequest: ResizeRequest) {const resizedImage = await this.imageResizerClient.resizeImage(resizeRequest).toPromise();return resizedImage.fileName;}}
Végül a main.ts fájlban létrehozzuk és indítjuk a NestJS alkalmazást. Az await app.listen(3000); sorral az alkalmazás a 3000-es porton figyel, lehetővé téve az API-hoz való hozzáférést.
TYPESCRIPT//grpc-picture-resize/src/main.tsimport { NestFactory } from '@nestjs/core';import { AppModule } from './app.module';async function bootstrap() {const app = await NestFactory.create(AppModule);await app.listen(3000);}bootstrap();
A ResizeController felelős a gRPC hívások fogadásáért és kezeléséért. A @GrpcMethod() dekorátorral jelölt resizeImage metódus a gRPC kliensektől érkező ResizeImage hívásokat fogadja. Ebben a metódusban hívódik meg a ResizeService által nyújtott képátméretezési funkció, amely egy ResizeRequest objektumot vár paraméterként, és egy ResizeResponse objektummal tér vissza.
TYPESCRIPT//resize/src/resize.controller.tsimport { Controller } from '@nestjs/common';import { GrpcMethod } from '@nestjs/microservices';import { ResizeService } from './resize.service';import { ResizeRequest, ResizeResponse } from 'proto/resize';@Controller()export class ResizeController {constructor(private readonly resizeService: ResizeService) {}@GrpcMethod('ImageResizer', 'ResizeImage')async resizeImage(resizeRequest: ResizeRequest): Promise<ResizeResponse> {return this.resizeService.resizeImage(resizeRequest);}}
A ResizeModule a kontroller és a szolgáltatás NestJS modulba való csomagolásáért felelős. Ez a modul biztosítja, hogy a kontroller és a szolgáltatás elérhető és használható legyen a mikroszolgáltatásban.
TYPESCRIPT//resize/src/resize.module.tsimport { Module } from '@nestjs/common';import { ResizeService } from './resize.service';import { ResizeController } from './resize.controller';@Module({controllers: [ResizeController],providers: [ResizeService],})export class ResizeModule {}
A ResizeService implementálja a képek tényleges átméretezését használva a sharp könyvtárat. A resizeImage metódus fogad egy ResizeRequest objektumot, amely tartalmazza a kép adatát (a Buffer formájában), valamint a kívánt szélességet és magasságot. A sharp segítségével átméretezi a képet, majd a lemezre menti a generált képet egy előre meghatározott könyvtárba. Végül visszatér egy ResizeResponse objektummal, amely tartalmazza a generált fájl nevét, valamint az átméretezett kép szélességét és magasságát.
TYPESCRIPT//resize/src/resize.service.tsimport { Injectable } from '@nestjs/common';import * as sharp from 'sharp';import { ResizeRequest, ResizeResponse } from 'proto/resize';import * as fs from 'fs';import * as path from 'path';@Injectable()export class ResizeService {private saveDirectory = path.join(__dirname, '../');async resizeImage(resizeRequest: ResizeRequest): Promise<ResizeResponse> {try {const fileName = `resized-${Date.now()}.jpg`;const outputPath = path.join(this.saveDirectory, fileName);const { data: resizedImage, info } = await sharp(Buffer.from(resizeRequest.image),).resize(resizeRequest.width, resizeRequest.height).toBuffer({ resolveWithObject: true });// Save to diskfs.writeFileSync(outputPath, resizedImage);return {fileName: fileName,resizedWidth: info.width,resizedHeight: info.height,};} catch (error) {console.error('Image resizing and saving failed: ', error.message);throw new Error(error.message);}}}
A bootstrap függvény indítja el a mikroszolgáltatást. Ebben az esetben a NestFactory.createMicroservice metódust használjuk a gRPC szerver létrehozására, konfigurálására és indítására. A transport beállítása Transport.GRPC-re van állítva, ami lehetővé teszi a NestJS számára, hogy gRPC protokollt használjon a kommunikációhoz. Az options objektumban megadjuk a proto fájl elérési útját és a csomag nevét, amely leírja a kommunikációra használt interfészt és üzenetformátumokat.
TYPESCRIPT//resize/src/main.tsimport { NestFactory } from '@nestjs/core';import { MicroserviceOptions, Transport } from '@nestjs/microservices';import { ResizeModule } from './resize.module';import { join } from 'path';async function bootstrap() {const app = await NestFactory.createMicroservice<MicroserviceOptions>(ResizeModule,{transport: Transport.GRPC,options: {package: 'resize',protoPath: join(__dirname, '../resize.proto'),},},);await app.listen();}bootstrap();
A kód egyszerűsége érdekében csak az image fájl nevét küldjük vissza. A kész módosított képhez pedig mentjük a localhost-on, ahogy a fentebbi kódban már megadtuk
Mikroszolgáltatás és kliens alkalmazás indítása: Először is indítsuk el a képátméretező mikroszolgáltatást és a kliens alkalmazást a következő parancsokkal:
POWERSHELLnpm run start:dev resize
POWERSHELLnpm run start:dev grpc-picture-resize
Tesztelés Postman vagy curl segítségével:
A rendszer teszteléséhez használhatjuk a Postman alkalmazást vagy a curl parancssori eszközt. A teszteléshez küldjünk egy POST kérést a kliens alkalmazás /resize végpontjára, megadva a kép URL-jét, a kívánt szélességet és magasságot a kérés törzsében.
Például, curl használatával:
POWERSHELLcurl -X POST
A sikeres képátméretezés után a megadott paraméterekkel átméretezett kép a resize alkalmazás által konfigurált helyi mappában lesz mentve. A kép fájlneve, amely tartalmazza az átméretezés időpontját, visszaküldésre kerül a kérés indítójának, lehetővé téve az eredmények ellenőrzését.
A gRPC használata képátméretezésre több előnnyel is jár, különösen mikroszolgáltatások esetén, vagy amikor a rendszer több különböző komponensből áll, amelyek közötti kommunikáció fontos szempont. A kód fejlesztésének egyik lehetősége, hogy a feltöltt képeket feltöltjük aws s3-ra és annak az url-jét küldjük vissza a felhasználónak
A teljes kód megtalálható:
https://github.com/balazsfaragodev/grpc-nestjs-tutorial-beginner
Oszd meg ezt a cikket
Indítsd a napod a legújabb technológiai áttörésekkel. Csatlakozz most, és merülj el az innovációban!