Nest.js简单入门p1

简介: Nest.js简单入门p1

Nest.js简单入门p1

文件作用

在service文件中写函数,在controller文件中调用。最后放在module文件中

controller文件

使用nest cil创建一个文件夹,里面有controller文件

nest generate controller
//或者简写
nest g co

@Controller() class装饰器工厂:参数为string或者string[],传入url地址

url地址中id的传递

在@Get() 方法装饰器工厂中传入:id

在函数中的参数中使用@Param() 参数装饰器工厂,传入id 这里的标识符要与@Get()装饰器的参数一致

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

@Controller('coffees')
export class CoffeesController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    return `this is the #${id} yeah`;
  }
}

//localhost:3000/coffees/dd
//this is the #dd yeah

使用Post

使用@Post() 装饰器 参数使用@Body() 装饰器

@Post('nice')
findTwo(@Body() body) {
  return body;
}

在postman中传入这个json,也能得到整个传入的json

{
    "name":"kevin",
    "age":20
}

如果只想接收一部分,可以向@Body()中传入key

@Post('nice')
findTwo(@Body('name') body: any) {
  return body;
}

//kevin

自定义状态码

我们使用get访问成功时,nest默认的状态码是200,post是201

我们也可以使用HttpCode() 方法装饰器来进行状态码的自定义

@Post('nice')
@HttpCode(HttpStatus.GONE)
findTwo(@Body() body: any) {
  return body;
}

由于nest是基于express的,所以我们也可以使用express的原生方法(不过不推荐这样使用)

@Get('yes')
getCoffee(@Res() response: any): void {
  response.status(303).send(`this is coffee`);
}

Patch和Delete

使用@Parch()装饰器更新 @Delete()装饰器删除

@Patch(':id')
update(@Param('id') id: string | number, @Body('name') body: string): string {
  return `this action is update #${id} coffee #${body}`;
  // this action is update #lll coffee #kevin
}

@Delete(':id')
remove(@Param('id') id: string | number): string {
  return `this action is remove #${id} coffee`; //this action is remove #lll coffee
}

Query参数

我们可以在方法中使用@Query() 参数装饰器来取到传入的query参数

@Get('yes')
getCoffee(@Query() paramQuery: any): string {
  const { limit, offset } = paramQuery;
  return `coffee's limit is #${limit}#, offset is #${offset}#`;
  //localhost:3000/coffees/yes?limit=20&offset=20
  //coffee's limit is #20#, offset is #20#
}

service文件

service文件是用来写函数的文件,也是nest的核心文件。将函数与controller分开更有利于项目的实现

我们可以使用nest cli来创建

nest generate service
//或者简写
nest g s

下面是使用例子:

coffee.entities

export class Coffee {
  id: string;
  name: string;
  brand: string;
  flavors: string[];
}

coffees.service.ts

import { Injectable } from '@nestjs/common';
import { Coffee } from './entities/coffee.entities';

@Injectable()
export class CoffeesService {
  private coffees: Coffee[] = [
    {
      id: '1',
      name: 'nest demo',
      brand: 'nest coffee',
      flavors: ['sweet', 'vanlilla'],
    },
  ];
  //输出所有的coffee
  findAll() {
    return this.coffees;
  }
  //输出指定id的coffee
  findOne(id: string) {
    return this.coffees.find((item) => item.id === id);
  }
  //添加新的coffee
  create(createDto: Coffee) {
    this.coffees.push(createDto);
  }
  update(id: string, updateDto: any) {}
  //删除指定id的coffee
  remove(id: string) {
    const coffeeIndex = this.coffees.findIndex((item) => item.id === id);
    if (coffeeIndex >= 0) {
      this.coffees.splice(coffeeIndex, 1);
    }
  }
}

coffees.controller.ts

import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
} from '@nestjs/common';
import { CoffeesService } from './coffees.service';
import { Coffee } from './entities/coffee.entities';

@Controller('coffees')
export class CoffeesController {
  constructor(private readonly coffeesService: CoffeesService) {}
  @Get('')
  getCoffee(): Coffee[] {
    return this.coffeesService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.coffeesService.findOne(id);
  }

  @Post('nice')
  create(@Body() body: any) {
    return this.coffeesService.create(body);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() body: any) {
    return this.coffeesService.update(id, body);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.coffeesService.remove(id);
  }
}

返回错误信息

在上例中,我们如果查找的id不存在,那么将没有返回值,所以我们需要优化一下。

使用HTTPException类,他有两个参数,第一个是错误信息,第二个是状态码。

//输出指定id的coffee
findOne(id: string): Coffee {
  const coffee = this.coffees.find((item) => item.id === id);
  if (!coffee) {
    throw new HttpException(`can't find #${id}#`, HttpStatus.NOT_FOUND);
  }
  return coffee;
}

我们也可以直接使用NotFoundException,他只有一个参数:错误信息,但是他的输出还会多一个error:Not Found

//输出指定id的coffee
findOne(id: string): Coffee {
  const coffee = this.coffees.find((item) => item.id === id);
  if (!coffee) {
    throw new NotFoundException(`can't find #${id}#`);
  }
  return coffee;
}

如果我们在前面抛出了错误,那么在访问的时候可以看到状态码500,nest服务器会报错。这对于我们程序中比较深的错误或者使用第三方库的时候有用。

//输出指定id的coffee
findOne(id: string): Coffee {
  throw `sss`;
  const coffee = this.coffees.find((item) => item.id === id);
  if (!coffee) {
    throw new NotFoundException(`can't find #${id}#`);
  }
  return coffee;
}

module文件

module文件作为一个功能模块,controller文件和service文件将会被放在里面。这样将会方便项目代码的管理

nest g module
//或者简写
nest g mo

module文件使用了@Module()装饰器,里面有四个可选参数(类型都为数组),其中:

  • imports:module文件
  • controllers:controller文件
  • providers:service文件
  • exports:导出其他模块需要共享的Providers

coffees.module.ts文件

import { Module } from '@nestjs/common';
import { CoffeesController } from './coffees.controller';
import { CoffeesService } from './coffees.service';

@Module({ controllers: [CoffeesController], providers: [CoffeesService] })
export class CoffeesModule {}

注意:由于上例的module后创建,所以要将App.module中的 coffees.controller和coffees.providers删除掉。不然将会执行两次实例。

DTO

DTO文件中没有任何逻辑,只是为了更好的约束值的传递。使用DTO可以让类型更加的安全

创建一个dto文件

nest g class coffees/dto/create-coffee.dto --no-spec

create-coffee.dto

export class CreateCoffeeDto {
  readonly id: string;
  readonly name: string;
  readonly brand: string;
  readonly flavors: string[];
}

update-coffee.dto

export class UpdateCoffeeDto {
  readonly name?: string;
  readonly brand?: string;
  readonly flavors?: string[];
}

controller文件

@Post('nice')
create(@Body() createCoffeeDto: CreateCoffeeDto) {
  return this.coffeesService.create(createCoffeeDto);
}

@Patch(':id')
update(@Param('id') id: string, @Body() updateCoffeeDto: UpdateCoffeeDto) {
  return this.coffeesService.update(id, updateCoffeeDto);
}

Pipes 管道 与 DTO

在main.ts中启用管道

app.useGlobalPipes(new ValidationPipe());

下载两个包

yarn add class-validator class-transformer

其中:class-validator可以让你使用DTO时,如果传值类型错误,会给你提供详细的错误信息

在create-coffee.dto.ts中使用:

import { IsString } from 'class-validator';

export class CreateCoffeeDto {
  @IsString()
  readonly id: string;

  @IsString()
  readonly name: string;

  @IsString()
  readonly brand: string;

  @IsString({ each: true })
  readonly flavors: string[];
}

在postman中测试:

// 输入
{
    "name": "year",
    "brand": "nest-ts"
}
//输出
{
    "statusCode": 400,
    "message": [
        "id must be a string",
        "each value in flavors must be a string"
    ],
    "error": "Bad Request"
}

这样,我们得到了详细的错误提示:id必须是string类型,flavor必须是string[]类型

我们重新修改过后:

// 成功录入
{
    "id": "2",
    "name": "nest",
    "brand": "coffee",
    "flavors": [
        "nice",
        "vanlilla"
    ]
}

为了不在update-coffee.dto.ts中也写同样的代码。nestjs给我们提供了一个包:mapped-types

yarn add @nestjs/mapped-types

我们让类继承PartialTyp(),参数为想要继承属性的class。继承的属性全部都为可选,类型也都是相同的。

update-coffee.dto.ts:

import { PartialType } from '@nestjs/mapped-types';
import { CreateCoffeeDto } from './create-coffee.dto';

export class UpdateCoffeeDto extends PartialType(CreateCoffeeDto) {}

coffees.service.ts:

// 更新指定id的coffee
update(id: string, updateDto: UpdateCoffeeDto) {
  let existingCoffee = this.findOne(id);
  const coffeeIndex = this.coffees.findIndex((item) => item.id === id);
  if (!existingCoffee) {
    throw new HttpException(`#${id}# is not found`, 401);
  }
  Object.assign(this.coffees[coffeeIndex], updateDto);
}

测试:

// 输入
{
    "name": 132,
    "brand": "coffee"
}
// 输出
{
    "statusCode": 400,
    "message": [
        "name must be a string"
    ],
    "error": "Bad Request"
}

当我们将name的值设为string类型时(如"name" : "ddwb"),就不会报错了。然后再查询:

{
    "id": "1",
    "name": "ddwb",
    "brand": "coffee",
    "flavors": [
        "sweet",
        "vanlilla"
    ]
}

ValidationPipe的更多用法

whitelist白名单

在使用creat方法创建对象时,如果输入了没有声明的属性并不会报错,而且录入进数据库。

我们并不想这样,所以我们可以使用ValidationPipe的whitelist,配合DTO来过滤掉没有声明的属性

main.ts:

app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
    }),
);
// 使用前
{
    "id": "2",
    "name": "year",
    "brand": "nest-ts",
    "flavors": [
        "nice"
    ],
    "isNotPromission": "bbc"
}
// 使用后
{
    "id": "2",
    "name": "year",
    "brand": "nest-ts",
    "flavors": [
        "nice"
    ]
}

forbidNonWhitelisted属性

我们还可以使用forbidNonWhitelisted属性

main.ts

app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
    }),
);

这样我们会得到错误提示:

{
    "statusCode": 400,
    "message": [
        "property isNotPromission should not exist"
    ],
    "error": "Bad Request"
}

transform

我们尝试检测CreateCoffeeDto类是否在createCoffeeDto原型链上

coffees.controller.ts:

@Post('nice')
create(@Body() createCoffeeDto: CreateCoffeeDto) {
  console.log(createCoffeeDto instanceof CreateCoffeeDto);//false
  return this.coffeesService.create(createCoffeeDto);
}

但意外的打印false

我们可以使用ValidationPope的transform属性

transform: true,

现在得到的createCoffeeDto instanceof CreateCoffeeDtotrue

相关文章
|
1月前
|
JavaScript API 图形学
一个案例带你从零入门Three.js,深度好文!
【8月更文挑战第1天】本教程无需任何Threejs知识!本教程以入门为主,带你快速了解Three.js开发
63 2
一个案例带你从零入门Three.js,深度好文!
|
4月前
|
存储 JavaScript 前端开发
【JavaScript技术专栏】JavaScript基础入门:变量、数据类型与运算符
【4月更文挑战第30天】本文介绍了JavaScript的基础知识,包括变量(var、let、const)、数据类型(Number、String、Boolean、Undefined、Null及Object、Array)和运算符(算术、赋值、比较、逻辑)。通过实例展示了如何声明变量、操作数据类型以及使用运算符执行数学和逻辑运算。了解这些基础知识对初学者至关重要,是进阶学习JavaScript的关键。
37 0
|
1月前
|
JavaScript 前端开发 NoSQL
使用Node.js进行后端开发入门
【8月更文挑战第10天】恭喜你完成了Node.js后端开发的入门之旅!这只是个开始,Node.js的世界远比这广阔。随着你对Node.js的深入学习和实践,你将能够构建更复杂、更强大的后端应用。不断探索、学习和实践,你将在Node.js的道路上越走越远。
|
1月前
|
Web App开发 JavaScript 前端开发
Node.js 入门
【8月更文挑战第4天】Node.js 入门
52 1
|
2月前
|
SQL 前端开发 JavaScript
前端三剑客之JavaScript基础入门
前端三剑客之JavaScript基础入门
|
3月前
|
XML JSON 前端开发
JavaScript入门宝典:核心知识全攻略(下)
JavaScript入门宝典:核心知识全攻略(下)
|
3月前
|
JavaScript 前端开发 UED
JavaScript入门宝典:核心知识全攻略(上)
JavaScript入门宝典:核心知识全攻略(上)
|
3月前
|
JavaScript
three.js入门第一个案例
three.js入门第一个案例
|
4月前
|
JavaScript
学习Node.js入门范例
然后,cmd中运行命令node E:/Test/server.js
35 2
|
3月前
|
缓存 前端开发 JavaScript
【JavaScript】JavaScript 中的闭包:从入门到精通
【JavaScript】JavaScript 中的闭包:从入门到精通
82 0