13.9.2021

NestJS Einführung 🤘

Was ist NestJS? 👨💻

  • Framework für skalierbare NodeJS Anwendung
  • Starker Einfluss von Angular
    • Konzepte
      • Dependency Injection
      • Seperation of Concern
  • "Out of the box" architecture
    • Skalierbarkeit
    • Testbarkeit
    • Wartbarkeit
  • Für Express & Fastify konfigurierbar

Setup 🖼

  • Über Nest CLI

    npm i -g @nestjs/cli
    nest new your-awesome-application

CLI 🍋

  • Das Nest CLI gibt klare Strukturen vor → Zeit wird gespart
    • Fragen wie Ordnerstruktur oder Dateibenennung werden somit beanwortet
  • Über nest --help bekommt man alle Information für die Erstellung der Dateien
nest --help
  • Folgender Befehler erstellt einen Controller:

    nest generate controller cat
  • Struktur

    NestJS%20%F0%9F%A4%98%203ee1b871962c4334a2d203fe5bd35bb7/Bildschirmfoto_2020-07-22_um_00.39.15.png

Routing 🛣

  • Routen werden über Decorator definiert
@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get() // localhost:3000/cats -> GET
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }

  @Get(':id') // localhost:3000/cats/12 -> GET with id of :id
  async findOne(@Param('id') id: string): Promise<Cat> {
    return this.catsService.findOne(id);
  }

  @Post() // localhost:3000/cats -> POST, create a cat with the content provided from your body
  async create(@Res() res, @Body() createCatDto: CreateCatDto): Promise<Cat> {
    return this.catsService.create(createCatDto);
  }

  @Patch(':id') // localhost:3000/cats -> PUT, update cat with the id :id 
  async updateProduct(id: string, @Body() createCatDto: CreateCatDto): Promise<Cat> {
    return this.catsService.update(id, createCatDto);
  }

  @Delete(':id') // localhost:3000/cats -> DELETE cat with id :id
  async delete(@Param('id') id: string): Promise<Cat> {
    return this.catsService.delete(id);
  }
}

Buisness Logic 🕴

  • Die Buisness Logic wird immer in einem passendem Service ausgelagert und beispielsweise hinterher in Controller injiziert (DI)
  • Controller sollten schlank sein
  • CRUD Service (mit Mongoose)
@Injectable()
export class CatsService {
  constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {}

  async create(createCatDto: CreateCatDto): Promise<Cat> {
    const createdCat = new this.catModel(createCatDto);
    
    return createdCat.save();
  }

  async findAll(): Promise<Cat[]> {
    return await this.catModel.find().exec();
  }

  async findOne(id: string): Promise<Cat> {
    return await this.catModel.findById(id).exec();
  }

  async update(id: string, createCatDto: CreateCatDto): Promise<Cat> {
    return this.catModel.findByIdAndUpdate(id, createCatDto, {new: true});
  }

  async delete(id: string): Promise<Cat> {
    return this.catModel.findByIdAndRemove(id);
  }
}

DTO

  • Data-Transfer-Objekt
  • Definiert wie ein Objekt transferiert werden darf
import { IsInt, IsString } from 'class-validator';

export class CreateCatDto {
  @IsString()
  readonly name: string;

  @IsInt()
  readonly age: number;

  @IsString()
  readonly breed: string;
}

Schemas

  • @schema() ordnet der Cat Klasse einer gleichnamigen MongoDB Sammlung zu (fügt am Ende es s hinzu)
  • Definition unseren Dokumentes in MongoDB
@Schema()
export class Cat extends Document {
  @Prop()
  name: string;

  @Prop()
  age: number;

  @Prop()
  breed: string;
}

export const CatSchema = SchemaFactory.createForClass(Cat);

MongoDB / Mongoose

const mongo__prod_uri = 'mongodb+srv://root:mypassword@nestjstestapp.mbynb.mongodb.net/NestJsTestApp?retryWrites=true&w=majority';
const mongo_uri = 'mongodb://localhost/cats';

// root module
@Module({
  controllers: [AppController],
  imports: [
    MongooseModule.forRoot(mongo_uri), // mongoose Anbindung
    ScheduleModule.forRoot(),
    CatsModule
  ],
  providers: [TasksService],
})
export class AppModule {}

Module

  • Controller & Services können in Modulen zusammengefasst werden

    • Vorteil

    → klare Definierung

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

    → Wiederverwendbarkeit von Modulen

    https://docs.nestjs.com/assets/Modules_1.png

Scheduled Jobs / Cronjobs

npm install --save @nestjs/schedule
  • Service Klasse erstellen

    • Über Decorators definieren
      • @cron(CronExpression.EVERY_5_MINUTES)
      • @interval(1000)
      • @timeout(1000)
    @Injectable()
    export class TasksService {
      private readonly logger = new Logger(TasksService.name);
    
      @Cron('45 * * * * *')
      handleCron() {
        this.logger.debug('Called every 45 seconds');
      }
    
      @Cron(CronExpression.EVERY_5_MINUTES)
      handleCoolCron() {
        this.logger.debug('Called every 5 Minutes');
      }
    }

Performance 🚀

  • Nach jeder PR läuft ein Performance Test https://github.com/nestjs/nest/runs/482105333
  • Oft wird die Performance von NestJS mit purem Express verglichen, dabei ist meistens das Resultat, dass Express an sich schneller ist. Dieser Vergleich ist aber nicht smart da Nest im Hintergrund viele weitere Prozesse übernimmt.
    • error handling middleware binding
    • body-parse middleware (json & extended urlencoded)
    • global express router
  • Seit Version 5.0 wird Fastify unterstützt
    • NestJS + Fastify > Pure Express 🚀

Open API 📄

npm install --save @nestjs/swagger swagger-ui-express
  • Einbindung in die Main Ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // swagger / open api setup
  const options = new DocumentBuilder()
      .setTitle('Nest Cats example')
      .setDescription('The cats API description')
      .setVersion('1.0')
      .addTag('cats')
      .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api', app, document);

  await app.listen(3000);
  console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();
  • localhost:3000/api

NestJS%20%F0%9F%A4%98%203ee1b871962c4334a2d203fe5bd35bb7/Untitled.png

S3 Upload

npm install aws-sdk multer multer-s3 --save
  • Multer ist eine Middleware von node für die Verarbeitung von "multipart/form-data", welche hauptsächlich zum Hochladen von Dateien verwendet wird

Präsentation unter notion.so: https://www.notion.so/NestJS-341e59e6bc494052ad1c052f7aa64d71

Zur Übersicht

Standort Hannover

newcubator GmbH
Bödekerstraße 22
30161 Hannover

Standort Dortmund

newcubator GmbH
Westenhellweg 85-89
44137 Dortmund