Skip to content

Commit

Permalink
feat: 提供统一响应的过滤器及拦截器
Browse files Browse the repository at this point in the history
  • Loading branch information
MZ-Dlovely committed Nov 3, 2024
1 parent a71934e commit 6911873
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
42 changes: 42 additions & 0 deletions apps/backend-nest/src/filters/http-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
import type { Response } from 'express';

import { BadRequestException, Catch, HttpException } from '@nestjs/common';

import { ResponseClass } from '#/interfaces/response';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const results = exception.getResponse() as any;

// eslint-disable-next-line unicorn/throw-new-error
const result = ResponseClass.Error(results.message);

// 参数校验错误,默认都是BadRequestException
const isArrayMessage = Array.isArray(results.message);
const isValidationError =
isArrayMessage &&
typeof results.message[0] === 'string' &&
results.message[0].includes('⓿');
if (exception instanceof BadRequestException && isValidationError) {
const message: Array<{ field: string; message: Array<string> }> = [];
results.message.forEach((item: string) => {
const [key, val] = item.split('⓿') as [string, string];
const findData = message.find((item) => item.field === key);
if (findData) {
findData.message.push(val);
} else {
message.push({ field: key, message: [val] });
}
});

result.error = message;
}

return response.status(status).json(result);
}
}
23 changes: 23 additions & 0 deletions apps/backend-nest/src/interceptor/transform.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type {
CallHandler,
ExecutionContext,
NestInterceptor,
} from '@nestjs/common';

import { Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { ResponseClass } from '#/interfaces/response';

@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, ResponseClass<T>>
{
intercept(
_: ExecutionContext,
next: CallHandler,
): Observable<ResponseClass<T>> {
return next.handle().pipe(map((data) => ResponseClass.Success(data)));
}
}
49 changes: 49 additions & 0 deletions apps/backend-nest/src/interfaces/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export class ResponseClass<T = any> {
constructor(
public code: number,
public data: T,
public error: any,
public message: string | string[],
) {}

static Error(message: string | string[], error: any = null) {
return new ResponseClass(-1, null, error, message);
}

static PageSuccess<T = any>(
page: number | string,
pageSize: number | string,
list: T[],
{ message = 'ok' } = {},
) {
const pageData = pagination(
Number.parseInt(`${page}`),
Number.parseInt(`${pageSize}`),
list,
);

const result = ResponseClass.Success({
items: pageData,
total: list.length,
});

result.message = message;

return result;
}

static Success<T = null>(data: T) {
return new ResponseClass(0, data, null, 'ok');
}
}

export function pagination<T = any>(
pageNo: number,
pageSize: number,
array: T[],
): T[] {
const offset = (pageNo - 1) * Number(pageSize);
return offset + Number(pageSize) >= array.length
? array.slice(offset)
: array.slice(offset, offset + Number(pageSize));
}

0 comments on commit 6911873

Please sign in to comment.