案例技术栈
- Nestjs
- Typescript
- mongoose
调试工具
- Apifox
在过去的很长一段时间里我封装了很多Service返回值的标准输出格式,但冠绝都不够优雅,最开始使用带泛型的函数包裹返回值。现在我发现使用Decorator 来重新实现让编码更优雅,也更语义化。
// format.ts
/*
* @Descripttion: Format Service Response
* @version: 0.0.0
* @Author: Minyoung
* @Date: 2022-03-27 21:09:58
* @LastEditors: Minyoung
* @LastEditTime: 2022-03-28 23:52:24
*/
/**
* 格式化列表查询返回结果
* @param ...rest
* @returns object { data, total, code, message }
*/
export function ListResponse() {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const fn = descriptor.value;
return {
get() {
return async (...rest) => {
const { data: result, total } = await fn.call(this, ...rest);
const data = result ? result : [];
const code = result ? 200 : 201;
const message = code === 200 ? 'success' : 'fail'
return Promise.resolve({ data, total: total || 0, code, message });
}
}
}
}
}
/**
* 格式化单查询返回结果
* @param rest
* @returns object { data, code, message }
*/
export function BasicResponse() {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const fn = descriptor.value;
return {
get() {
return async (...rest) => {
const { data } = await fn.call(this, ...rest);
const code = data ? 200 : 201;
const message = code === 200 ? 'success' : 'fail'
return Promise.resolve({ data, code, message });
}
}
}
}
}
/**
* 格式化创建返回结果
* @param rest
* @returns object { result, code, message }
*/
export function CreateResponse() {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const fn = descriptor.value;
return {
get() {
return async (...rest) => {
const { result } = await fn.call(this, ...rest);
const code = result ? 200 : 201;
const message = code === 200 ? 'success' : 'fail'
return Promise.resolve({ result, code, message });
}
}
}
}
}
/**
* 格式化更新返回结果
* @param rest
* @returns object { result, code, message }
*/
export function UpdateResponse() {
// {
// "acknowledged": true,
// "modifiedCount": 1,
// "upsertedId": null,
// "upsertedCount": 0,
// "matchedCount": 1
// }
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const fn = descriptor.value;
return {
get() {
return async (...rest) => {
const { result } = await fn.call(this, ...rest);
const code = result.modifiedCount >= 1 ? 200 : 201;
const message = code === 200 ? 'success' : 'fail'
return Promise.resolve({ result, code, message });
}
}
}
}
}
/**
* 格式化删除返回结果
* @param rest
* @returns object { result, code, message }
*/
export function DeleteResponse() {
// {
// acknowledged: true,
// deletedCount: 0
// }
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const fn = descriptor.value;
return {
get() {
return async (...rest) => {
const { result } = await fn.call(this, ...rest);
const code = result.deletedCount >= 1 ? 200 : 201;
const message = code === 200 ? 'success' : 'fail'
return Promise.resolve({ result, code, message });
}
}
}
}
}
应用于
// product.service.ts
/*
* @Descripttion: 产品 Serive
* @version: 0.0.0
* @Author: Minyoung
* @Date: 2022-03-26 20:48:07
* @LastEditors: Minyoung
* @LastEditTime: 2022-03-28 23:51:50
*/
import { Injectable } from '@nestjs/common';
import { CreateProductDto } from './dto/create-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
import { Product, ProductDocument } from './entities/product.entity';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { ListResponse, BasicResponse, CreateResponse, UpdateResponse, DeleteResponse } from '../utils/format'
@Injectable()
export class ProductsService {
@InjectModel(Product.name) private readonly product: Model<ProductDocument>
constructor() {}
@CreateResponse()
async create(createProductDto: CreateProductDto) {
const result = await this.product.create(createProductDto);
return { result };
}
@ListResponse()
async findAll() {
const data = await this.product.find().exec();
const total = await this.product.countDocuments().exec();
return { data, total };
}
@BasicResponse()
async findOne(id: number) {
const data = await this.product.findById(id).exec();
return { data };
}
@UpdateResponse()
async update(_id: string, updateProductDto: UpdateProductDto) {
const result = await this.product.updateOne({ _id }, {
$set: updateProductDto
});
return { result };
}
@DeleteResponse()
async remove(_id: string) {
const result = await this.product.deleteOne({ _id }).exec();
return { result };
}
}
调试结果示例:
列表返回[success]
{
"data": [
{
"comments": [],
"_id": "624034a87da67ec5435bb04a",
"title": "98年可乐",
"price": 198,
"sale": 0,
"timeLimit": 100,
"banners": [],
"createdAt": 1648374952937,
"updatedAt": 1648471880892
}
],
"total": 1,
"code": 200,
"message": "success"
}
删除返回[fail]
{
"result": {
"acknowledged": true,
"deletedCount": 0
},
"code": 201,
"message": "fail"
}