I have a Dto that I want to enable the service layer to filter: The method selectFields
takes an array of field names that should be returned, the other properties will be removed.
What is a short way to enumerate the properties on the class so I can loop through them and set the filtered ones to null?
In the BaseDto I take care of cleaning falsy values (well I need the same function here too as a matter of fact).
class UserServiceDto extends BaseDto {
constructor(userDto) {
super();
this.fbUserId = userDto.fbUserId;
this.fbFirstName = userDto.fbFirstName;
this.fbLastName = userDto.fbLastName;
this.gender = userDto.gender;
this.birthdate = userDto.birthdate;
this.aboutMe = userDto.aboutMe;
this.deviceToken = userDto.deviceToken;
this.refreshToken = userDto.refreshToken;
this.updatedAt = userDto.updatedAt;
this.createdAt = userDto.createdAt;
}
selectFields(fields) {
// --> what's your take?
}
toJson() {
return super.toJson();
}
}
Edit:
The service layer receives a dto from repository layer including all database fields. The ServiceLayerDto aims at filtering out fields that are not required by the web api (or should not be exposed as a security measure eg PK field, isDeleted, etc). So the result would I'm looking at the end of a service method for would look something like:
return new UserServiceDto(userDto)
.selectFields('fbUserId', 'fbFirstName', 'fbLastName', 'birthdate', 'aboutMe', 'updatedAt', 'createdAt')
.toJson();
The return value would be a plain json object that the web layer (controller) sends back to the http client.
If you are ok with spread operator, you may try following approach:
class UserServiceDto {
constructor() {
this.a = 1;
this.b = 2;
this.c = 3;
}
selectFields(...fields) {
const result = {};
fields.forEach(key => result[key] = this[key]);
return result;
}
}
new UserServiceDto().selectFields('a', 'c'); // {a: 1, c: 3}
Looking to super.toJson()
call, I think that it would not work due to the result of my selectFields()
call would not be an instance of UserServiceDto
class. There are some possible ways from this point I see:
UserServiceDto
object inside selectFields()
body, remove all fields that not listed in the ...fields
array (javascript delete
is okey) and return it; UserServiceDto
constructor params to save positive logic on selectFields()
, and pass to constructor only that props that need to be set up; in this case instantiating a temporary object will not require properties removing; toJson
method, or better add a new signature, which would allow to pass fields array and then put current selectFields
logic inside toJson
method (and remove selectFields
method at all): new UserServiceDto().toJson('a', 'c')
... Purely for info, I ultimately changed my app architecture.
The repository returns a Dto to the service layer (dto being mapped directly from the sql queries).
The service builds a static View based on the Dto and returns it to the web layer (represented by a plain json object).
In my directory structure, I have:
- service
-- views
--- index.js
--- UserInfo.js
The view is a simple filter. Eg UserInfoView:
exports.build = ({ fbUserId, fbFirstName, fbLastName, gender, birthdate, aboutMe, updatedAt, createdAt }) => {
return {
fbUserId,
fbFirstName,
fbLastName,
gender,
birthdate,
aboutMe,
updatedAt,
createdAt,
};
};
Using the view, eg UserInfoView in the service looks like this:
const Views = require('../service/views');
exports.findActiveByUserId = async (pUserId) => {
const userDto = await UserRepository.findActiveByUserId(pUserId);
if (!userDto) {
throw new ServiceError(Err.USER_NOT_FOUND, Err.USER_NOT_FOUND_MSG);
}
return Views.UserInfo.build(userDto.toJson());
};
I think that this is much more descriptive compared to my initial take on the problem. Also, it keeps the data objects plain (no additional methods required).
It is unfortunate that I can't require receiving an type (View) in the web layer, I might be able to solve that problem with Typescript later on.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.