NestJS 序列化从 snake_case 到 camelCase
NestJS serialization from snake_case to camelCase
我想实现自动serialization/deserialization of JSON request/response body for NestJS controllers,准确的说,自动转换snake_case
request body JSON keys camelCase
在我的控制器处理程序中收到,反之亦然。
我发现使用 class-transformer
的 @Expose({ name: 'selling_price' })
,如下例所示(我使用的是 MikroORM):
// recipe.entity.ts
@Entity()
export class Recipe extends BaseEntity {
@Property()
name: string;
@Expose({ name: 'selling_price' })
@Property()
sellingPrice: number;
}
// 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);
}
}
// example request body
{
"name": "Recipe 1",
"selling_price": 50000
}
// log on the RecipeController.createOne handler method
{ name: 'Recipe 1',
selling_price: 50000 }
// what I wanted on the log
{ name: 'Recipe 1',
sellingPrice: 50000 }
可以看出@Expose
注解完美,但更进一步我希望能够将其转换为实体上的属性名称:sellingPrice
,所以我可以直接通过已解析的请求正文到我的服务和我的存储库方法 this.recipeRepository.create(data)
。当前情况是 sellingPrice
字段将为空,因为存在 selling_price
字段。如果我不使用 @Expose
,请求 JSON 将需要写在 camelCase
上,这不是我喜欢的。
我可以做 DTO 和构造函数以及分配字段,但我认为这是相当重复的,并且由于我的命名偏好,我将有很多字段需要转换:snake_case
on JSON 和所有 JS/TS 部分的数据库列和 camelCase
。
有什么方法可以让我干净利落地完成这个把戏吗?也许已经有解决方案了。也许是将所有 snake_case
转换为 camel_case
的全局拦截器,但我也不确定如何实现。
谢谢!
您可以使用 ORM 中的 mapResult()
方法,它负责将原始数据库结果(对您来说是 snake_case)映射到实体 属性 名称(对您来说是驼峰命名法) :
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 }`
此方法基于实体元数据运行,从 fieldName
更改键(默认为基于所选命名策略的值)。
我想实现自动serialization/deserialization of JSON request/response body for NestJS controllers,准确的说,自动转换snake_case
request body JSON keys camelCase
在我的控制器处理程序中收到,反之亦然。
我发现使用 class-transformer
的 @Expose({ name: 'selling_price' })
,如下例所示(我使用的是 MikroORM):
// recipe.entity.ts
@Entity()
export class Recipe extends BaseEntity {
@Property()
name: string;
@Expose({ name: 'selling_price' })
@Property()
sellingPrice: number;
}
// 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);
}
}
// example request body
{
"name": "Recipe 1",
"selling_price": 50000
}
// log on the RecipeController.createOne handler method
{ name: 'Recipe 1',
selling_price: 50000 }
// what I wanted on the log
{ name: 'Recipe 1',
sellingPrice: 50000 }
可以看出@Expose
注解完美,但更进一步我希望能够将其转换为实体上的属性名称:sellingPrice
,所以我可以直接通过已解析的请求正文到我的服务和我的存储库方法 this.recipeRepository.create(data)
。当前情况是 sellingPrice
字段将为空,因为存在 selling_price
字段。如果我不使用 @Expose
,请求 JSON 将需要写在 camelCase
上,这不是我喜欢的。
我可以做 DTO 和构造函数以及分配字段,但我认为这是相当重复的,并且由于我的命名偏好,我将有很多字段需要转换:snake_case
on JSON 和所有 JS/TS 部分的数据库列和 camelCase
。
有什么方法可以让我干净利落地完成这个把戏吗?也许已经有解决方案了。也许是将所有 snake_case
转换为 camel_case
的全局拦截器,但我也不确定如何实现。
谢谢!
您可以使用 ORM 中的 mapResult()
方法,它负责将原始数据库结果(对您来说是 snake_case)映射到实体 属性 名称(对您来说是驼峰命名法) :
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 }`
此方法基于实体元数据运行,从 fieldName
更改键(默认为基于所选命名策略的值)。