Skip to main content

请求校验

校验数据类型

运行时校验TypeScript类型

Summer支持运行时校验TypeScript类型,所以请求DTO只需要按正常的TypeScript写法就可以了,必须写成class类,不能是interface

支持的验证类型

类型说明
boolean布尔型
number数字型
string字符串型
int整形
bigint大整型
Date日期类型
enum枚举(支持数字枚举和字符串枚举)
't1' | 't2'字符串联合类型
{object}JSON对象
array[]数组
generic<T>简单的泛型

数据限制装饰器

装饰器用途
?选传参数
!使用在 string 不允许为空白(多个空格)
@Min(min: number, message?: string | (val) => string)使用在 number/int/bigint 限定最小值
@Max(max: number, message?: string | (val) => string)使用在 number/int/bigint 限定最大值
@MinLen(minLen: number, message?: string | (val) => string)使用在 string/array[] 限定最小长度
@MaxLen(maxLen: number, message?: string | (val) => string)使用在 string/array[] 限定最大长度
@Len(fixedLen: number, message?: string | (val) => string)使用在 string/array[] 限定固定长度
@Len(minLen: number, maxLen: number, message?: string | (val) => string)使用在 string/array[] 限定长度范围
@Email(message?: string | (val) => string)使用在 string 限定必须是电子邮件格式
@Pattern(regexp :RegExp, message?: string | (val) => string)使用在 string 匹配正则
@Validate(func: (val: any) => boolean | string )自定义验证,验证函数返回 true 时代表验证通过,
返回字符串 "错误信息" 表示验证失败。

请求验证例子

src/dto/request/book.ts
enum BookType {
Fiction = 0,
Education = 1
}

class AddBookRequest {
// 验证 title 必须是字符串,而且是个选传参数
title?: string
// 验证 author 必须是字符串
author: string
// 验证 type 必须是 "Fiction" 或 "Education"
type: BookType
// 验证 pageCount 必须是整形
pageCount: int
}
src/controller/BookController.ts
import { Controller, Post, Body } from '@summer-js/summer'
import { AddBookRequest } from '../dto/request/book'

@Controller('/v1')
export class BookController {
@Post('/books')
add(@Body addBookRequest: AddBookRequest) {
console.log(addBookRequest)
}
}

类型验证

整形验证

int 不是TS/JS的基本类型,这是 Summer 扩展用于做请求验证的类型,在常规代码中int等同于 number.

src/controller/BookController.ts
import { Controller, Get, PathParam } from '@summer-js/summer'

@Controller
export class BookController {
@Get('/books/:inx')
book(@PathParam inx: int) {
const books = ['Harry Potter', 'The Great Gatsby', 'Dune']
return books[inx]
}
}
Get http://127.0.0.1:8801/todos/1.5
{
message: "Validation Failed",
errors: [
{
param: "inx",
message: "'1.5' is not an integer"
}
]
}

枚举验证

枚举类型验证传入值必须是枚举的其中一个key值

src/controller/BookController.ts
import { Controller, Get, Query } from '@summer-js/summer'

enum BookType {
Fiction = 0,
Education = 1
}

@Controller
export class BookController {
@Get('/books')
addBook(@Query type: BookType) {
if (type === BookType.Education) {
console.log('Searching Education Books...')
} else if (type === BookType.Fiction) {
console.log('Searching Fiction Books...')
}
}
}
GET http://127.0.0.1:8801/books?type=Romance
{
"message":"Validation Failed",
"errors":[
{
"param":"type",
"message":"'Romance' is not in [\"Fiction\",\"Education\"]"
}
]
}
GET http://127.0.0.1:8801/books?type=Fiction
Searching Fiction Books...

日期验证

日期验证传入的格式是否为日期格式例如 '2022-10-01' 或 '2022-10-01 12:00:00',亦可以使用时间戳 '1355270400000' 或 1355270400000

src/controller/BookController.ts
import { Controller, Get, Query } from '@summer-js/summer'

@Controller
export class BookController {
@Get('/books')
addBook(@Query createDate: Date) {
console.log('Searching Books in created in ' + createDate)
}
}
GET http://127.0.0.1:8801/books?createDate=xxx
{
"message":"Validation Failed",
"errors":[
{
"param":"createDate",
"message":"error parsing 'xxx' to Date"
}
]
}

布尔值验证

字符串 'true'/'false' '0'/'1', 数字 0/1 都可以用于验证通过并转成布尔型

Validation boolean query data
import { Controller, Get, Query } from '@summer-js/summer';

@Controller
export class ExampleController {
@Get('/boolean-test')
hello(@Query isDone: boolean) {
console.log(typeof isDone, isDone);
}
}
GET http://localhost:8801/boolean-test?isDone=true
boolean true
GET http://localhost:8801/boolean-test?isDone=0
boolean false

数字型数组验证

带逗号的字符串 "1,3,10" 可以通过int[]/number[]的验证

src/controller/BookController.ts
import { Controller, Delete, PathParam } from '@summer-js/summer'

@Controller
export class BookController {
@Delete('/books/:ids')
deleteBooks(@PathParam ids: int[]) {
console.log('Delete Books id in ' + JSON.stringify(ids))
}
}
http://127.0.0.1:8801/books/12,15,31
Delete Books id in [12,15,31]

数据约束

import { Controller, Post, Body, Min, MaxLen  } from '@summer-js/summer';

enum BookType {
Fiction = 0,
Education = 1
}

class AddBookRequest {
title: string;

// no more than 50 chars
@MaxLen(50)
author: string;

type: BookType;

// pageCount must bigger than 0
@Min(1)
pageCount: int;
}

@Controller('/v1')
export class BookController {
@Post('/books')
add(@Body addBookRequest: AddBookRequest) {
console.log(addBookRequest);
}
}

必传与选传

必传与选传

使用 '?' 标记的字段为选传参数,选传参数可以给默认值。
Summer的选传必须给API接口做了最佳适配,必传代表了必须要有数据,所以必传还有非空的概念。不写 '?' 的传参在传空字符串的时候不会验证通过。

class PersonRequest{
name: string
age?: number = 12
}

notice the '?' optional token also works in method params

@Get(/books)
addBooks(@Query keyword?: string, @Query pageNumber = 1){
// code
}

部分更新

src/dto/request/book.ts
export class Book {
title: string;
author: Person;
}
src/controller/BookController.ts
import { Controller, Patch, Body } from '@summer-js/summer';
import { Book } from '../dto/request/book'

@Controller
export class BookController {
@Patch('/books/:id')
updateBook(@Body book: Partial<Book>) {
console.log(book);
}
}

对象体验证

src/dto/request/book.ts
export enum Gender {
Female = 1,
Male = 2
}

export class Person {
name: string;
age: int;
gender: Gender;
}

export class Book {
title: string;
author: Person;
}
import { Controller, Post, Body } from '@summer-js/summer';
import { Book } from '../dto/request/book'

@Controller
export class BookController {
@Post('/books')
addBook(@Body book: Book) {
console.log(typeof book, book);
}
}

对象体数组验证

src/dto/request/book.ts
export class Book {
title: string;
author: string;
}
src/controller/BookController.ts
import { Controller, Post, Body } from '@summer-js/summer';
import { Book } from '../dto/request/book'

@Controller
export class BookController {
@Post('/books')
addBooks(@Body param: Book[]) {
console.log(typeof param, param);
}
}

类继承验证

src/dto/request/animal.ts
class Animal {
name: string
weight: number
}

export class Dog extends Animal {
noseLength: number
eyesColor: 'blue' | 'brown'
}
src/controller/AnimalController.ts
import { Controller, Post, Body } from '@summer-js/summer'
import { Dog } from '../dto/request/animal'

@Controller
export class AnimalController {
@Post('/dogs')
add(@Body dog: Dog) {
console.log(typeof dog, dog)
}
}

自定义验证

src/dto/request/book.ts
import { Validate } from '@summer-js/summer'

export class Book {
@Validate((val: string) => {
if(val.substring(0, 1).toUpperCase() === val.substring(0, 1)){
// return true to pass validation
return true
}
// or return an error message
return "Title must starts with uppercase letter"
})
title: string
}
src/controller/BookController.ts
import { Controller, Body, Post } from '@summer-js/summer'
import { Book } from '../dto/request/book'

@Controller
export class BookController {
@Post('/books')
detail(@Body book: Book) {
return book
}
}

简单的泛型验证

src/dto/request/animal.ts
export class Dog {
name: string
weight: number
}

export class Cat {
name: string
tailLength: number
}

export class AnimalRequest<T>{
obj: T
count: number
}
src/controller/AnimalController.ts
import { Controller, Post, Body } from '@summer-js/summer'
import { Dog, Cat, AnimalRequest } from '../dto/request/animal'

@Controller
export class AnimalController {
@Post('/dogs')
addDog(@Body dog: AnimalRequest<Dog>) {
console.log(dog)
}

@Post('/cats')
addCat(@Body cat: AnimalRequest<Cat>) {
console.log(cat)
}
}
Summer中的泛型验证

Summer 只支持简单的泛型.
复杂的泛型无法验证(包扩多层嵌套,复杂结构)


class TObj<T>{
a: T
}

class PObj{
a: number
}

class Obj<T, K, G> {
field1: T
field2: K
field3: G
filed4: TObj<int>
}

// 可以验证
@Post
api(@Body body: Obj<int[], string, boolean>) { }

// 可以验证
@Post
api(@Body body: Obj<int[], string, PObj>) { }

// 不可使用,可能会导致程序错误
@Post
api(@Body body: Obj<int[], string, TObj<TObj<TObj<number>>>>) { }