如何在 Loopback 4 中设置一个单独的 DTO 而不是 Persistable 模型
How to setup a separate DTO other than Persistable Model in Loopback 4
考虑这个 lb4 模型
@model({
name: 'users'
})
export class User extends Entity {
@property({
type: 'number',
id: true,
})
id: number;
@property({
type: 'string',
required: true,
})
first_name: string;
@property({
type: 'string',
})
middle_name?: string;
@property({
type: 'string',
})
last_name?: string;
@property({
type: 'string',
required: true,
})
username: string;
@property({
type: 'string',
})
email?: string;
@property({
type: 'string',
})
phone?: string;
@property({
type: 'string',
required: true,
})
password: string;
@property({
type: 'string',
})
external_id: string;
@belongsTo(() => UserTenant)
created_by: number;
@belongsTo(() => UserTenant)
modified_by: number;
constructor(data?: Partial<User>) {
super(data);
}
}
目前,如果我们使用 lb4 cli 为此模型创建一个存储库和控制器,它将使用与 input/output 相同的模型生成路由方法 CRUD。然而,我们想要的是有一个单独的 DTO 模型(非持久化到数据库)被用作控制器的 input/output DTO,不包括属性密码,created_by 和 modified_by。一种方法是手动创建这样一个模型 class 并记下一个转换器 class ,它将 UserDTO 对象转换为上面的 User 模型(复制各个属性)。但这似乎是一种开销。此外,我们希望对更多模型进行此操作。因此,以这种方式进行操作似乎不是正确的方法。 lb4 是否提供了更好的方法来实现这一目标?
目前看来,现在可以在 LB4 中使用 "hide" 属性。然后我最终用新实体 HideableEntity(扩展实体)修改了实体 class。在 HideableEntity 中,我修改了 toJson() 函数,如下所示:
import {Entity, AnyObject} from '@loopback/repository';
import {Options} from '@loopback/repository/src/common-types';
export abstract class HideableEntity extends Entity {
/**
* Serialize into a plain JSON object
*/
toJSON(): Object {
const def = (<typeof HideableEntity>this.constructor).definition;
if (def == null || def.settings.strict === false) {
return this.toObject({ignoreUnknownProperties: false});
}
const json: AnyObject = {};
for (const p in def.properties) {
if (p in this) {
json[p] = asJSON((this as AnyObject)[p]);
}
}
return json;
}
/**
* Convert to a plain object as DTO
*/
toObject(options?: Options): Object {
const def = (<typeof HideableEntity>this.constructor).definition;
let obj: AnyObject;
if (options && options.ignoreUnknownProperties === false) {
obj = {};
for (const p in this) {
if (def != null && def.properties[p] && def.properties[p]['hide']) {
continue;
}
let val = (this as AnyObject)[p];
obj[p] = asObject(val, options);
}
} else {
obj = this.toJSON();
}
return obj;
}
}
function asJSON(value: any): any {
if (value == null) return value;
if (typeof value.toJSON === 'function') {
return value.toJSON();
}
// Handle arrays
if (Array.isArray(value)) {
return value.map(item => asJSON(item));
}
return value;
}
function asObject(value: any, options?: Options): any {
if (value == null) return value;
if (typeof value.toObject === 'function') {
return value.toObject(options);
}
if (typeof value.toJSON === 'function') {
return value.toJSON();
}
if (Array.isArray(value)) {
return value.map(item => asObject(item, options));
}
return value;
}
然后现在在我的模型扩展 HideableEntity 中,我添加 属性 hide: true
并且它不会被添加到 JSON 输出:
export class User extends HideableEntity {
@property({
type: 'number',
id: true,
required: false,
})
id: number;
@property({
type: 'string',
required: true,
})
email: string;
@property({
type: 'string',
required: true,
hide: true,
})
password: string;
[...]
在上述情况下,密码将被隐藏。
考虑这个 lb4 模型
@model({
name: 'users'
})
export class User extends Entity {
@property({
type: 'number',
id: true,
})
id: number;
@property({
type: 'string',
required: true,
})
first_name: string;
@property({
type: 'string',
})
middle_name?: string;
@property({
type: 'string',
})
last_name?: string;
@property({
type: 'string',
required: true,
})
username: string;
@property({
type: 'string',
})
email?: string;
@property({
type: 'string',
})
phone?: string;
@property({
type: 'string',
required: true,
})
password: string;
@property({
type: 'string',
})
external_id: string;
@belongsTo(() => UserTenant)
created_by: number;
@belongsTo(() => UserTenant)
modified_by: number;
constructor(data?: Partial<User>) {
super(data);
}
}
目前,如果我们使用 lb4 cli 为此模型创建一个存储库和控制器,它将使用与 input/output 相同的模型生成路由方法 CRUD。然而,我们想要的是有一个单独的 DTO 模型(非持久化到数据库)被用作控制器的 input/output DTO,不包括属性密码,created_by 和 modified_by。一种方法是手动创建这样一个模型 class 并记下一个转换器 class ,它将 UserDTO 对象转换为上面的 User 模型(复制各个属性)。但这似乎是一种开销。此外,我们希望对更多模型进行此操作。因此,以这种方式进行操作似乎不是正确的方法。 lb4 是否提供了更好的方法来实现这一目标?
目前看来,现在可以在 LB4 中使用 "hide" 属性。然后我最终用新实体 HideableEntity(扩展实体)修改了实体 class。在 HideableEntity 中,我修改了 toJson() 函数,如下所示:
import {Entity, AnyObject} from '@loopback/repository';
import {Options} from '@loopback/repository/src/common-types';
export abstract class HideableEntity extends Entity {
/**
* Serialize into a plain JSON object
*/
toJSON(): Object {
const def = (<typeof HideableEntity>this.constructor).definition;
if (def == null || def.settings.strict === false) {
return this.toObject({ignoreUnknownProperties: false});
}
const json: AnyObject = {};
for (const p in def.properties) {
if (p in this) {
json[p] = asJSON((this as AnyObject)[p]);
}
}
return json;
}
/**
* Convert to a plain object as DTO
*/
toObject(options?: Options): Object {
const def = (<typeof HideableEntity>this.constructor).definition;
let obj: AnyObject;
if (options && options.ignoreUnknownProperties === false) {
obj = {};
for (const p in this) {
if (def != null && def.properties[p] && def.properties[p]['hide']) {
continue;
}
let val = (this as AnyObject)[p];
obj[p] = asObject(val, options);
}
} else {
obj = this.toJSON();
}
return obj;
}
}
function asJSON(value: any): any {
if (value == null) return value;
if (typeof value.toJSON === 'function') {
return value.toJSON();
}
// Handle arrays
if (Array.isArray(value)) {
return value.map(item => asJSON(item));
}
return value;
}
function asObject(value: any, options?: Options): any {
if (value == null) return value;
if (typeof value.toObject === 'function') {
return value.toObject(options);
}
if (typeof value.toJSON === 'function') {
return value.toJSON();
}
if (Array.isArray(value)) {
return value.map(item => asObject(item, options));
}
return value;
}
然后现在在我的模型扩展 HideableEntity 中,我添加 属性 hide: true
并且它不会被添加到 JSON 输出:
export class User extends HideableEntity {
@property({
type: 'number',
id: true,
required: false,
})
id: number;
@property({
type: 'string',
required: true,
})
email: string;
@property({
type: 'string',
required: true,
hide: true,
})
password: string;
[...]
在上述情况下,密码将被隐藏。