NestJS从snake_case序列化到camelCase

Dav*_*ael 6 serialization nestjs class-transformer mikro-orm

我想为 NestJS 控制器实现 JSON 请求/响应正文的自动序列化/反序列化,准确地说,自动将snake_case请求正文 JSON 键转换为camelCase在我的控制器处理程序处接收,反之亦然。

我发现使用class-transformer's @Expose({ name: 'selling_price' }),如下例所示(我正在使用 MikroORM):

// recipe.entity.ts
@Entity()
export class Recipe extends BaseEntity {
  @Property()
  name: string;
  
  @Expose({ name: 'selling_price' })
  @Property()
  sellingPrice: number;
}
Run Code Online (Sandbox Code Playgroud)
// recipe.controller.ts
@Controller('recipes')
export class RecipeController {
  constructor(private readonly service: RecipeService) {}

  @Post()
  async createOne(@Body() data: Recipe): Promise<Recipe> {
    console.log(data);
    return this.service.createOne(data);
  }
}
Run Code Online (Sandbox Code Playgroud)
// example request body
{
    "name": "Recipe 1",
    "selling_price": 50000
}
Run Code Online (Sandbox Code Playgroud)
// log on the RecipeController.createOne handler method
{ name: 'Recipe 1',
  selling_price: 50000 }

// what I wanted on the log
{ name: 'Recipe 1',
  sellingPrice: 50000 }
Run Code Online (Sandbox Code Playgroud)

可以看出,@Expose注释工作得很好,但更进一步,我希望能够将其转换为实体上的属性名称:sellingPrice,这样我就可以直接将解析后的请求正文传递给我的服务和我的存储库方法this.recipeRepository.create(data)。当前的情况是该sellingPrice字段将为空,因为存在该selling_price字段。如果我不使用@Expose,则需要写入请求 JSON camelCase,而这不是我喜欢的。

我可以执行 DTO 和构造函数并分配字段,但我认为这相当重复,并且由于我的命名偏好,我将有很多字段需要转换:snake_case在 JSON 和数据库列以及camelCase所有 JS/TS 部分上。

有什么办法可以干净利落地完成这个技巧吗?也许已经有解决方案了。也许是一个将所有snake_case内容转换为的全局拦截器camel_case,但我也不太确定如何实现一个。

谢谢!

Mar*_*mek 3

您可以使用mapResult()ORM 中的方法,该方法负责将原始数据库结果(对于您来说是 Snake_case)映射到实体属性名称(对于您来说是 CamelCase):

const meta = em.getMetadata().get('Recipe');
const data = {
  name: 'Recipe 1',
  selling_price: 50000,
};
const res = em.getDriver().mapResult(data, meta);
console.log(res); // dumps `{ name: 'Recipe 1', sellingPrice: 50000 }`
Run Code Online (Sandbox Code Playgroud)

此方法基于实体元数据进行操作,更改键fieldName(默认为基于所选命名策略的值)。