Say I'm building my own backend framework (really I'm just learning) and I have a simple class:
class User {
String email
String passwordHash
Date birthdate
Int getAge() {
Duration dt = Date.today() - birthdate
return dt.years
}
// Imagine more methods and things like `email` validation etc.
}
To create objects of this type, I obviously don't use passwordHash but need the initial raw password instead (to hash it on the server side):
struct UserCreationDto {
String email
String rawPassword
Date birthdate
}
To update objects of this type, I need yet another type because maybe email and birthdate can't be changed after the user is created:
struct UserUpdationDto {
String rawPassword
// Imagine there are other fields like `profilePicture` or whatever
}
When the user visits his own profile settings, he needs to see most of the existing data, but maybe not passwordHash:
struct UserSelfDto {
String email
Date birthdate
}
Yet when the data is displayed to another user, some other "secret" fields like exact birthdate need to be hidden as well:
struct UserPublicDto {
String email
Int age // Others can only see your age, not exact date
}
And finally to store/load users to/from say a database or a JSON file, I need something similar to CreationDto but with the password hashed instead of the raw one:
struct UserStorageDto {
String email
String passwordHash
Date birthdate
}
So initially I thought I'd get away with a simple mapper class:
interface Mapper<T, Dto> {
Dto toDto(T object)
void updateObject(T object, Dto dto)
}
But now it looks like I need my mappers to have a dozen methods to support all edge cases and DTO types (arrow directions matter):
- Is my assumption correct, or am I missing something here?
- Do I really need a new type and a mapper function for every single action that can be taken on the user?
- How do other existing frameworks implement support for so many different types?

Userfor everythingUserto external APIs, otherwise they can just access all secret fields and change passwords and whatever. Also I can't even transmit it over protocols like HTTP like that, I need to convert it to JSON first anyways?CreateUserRequestorUserInfoconveys a lot more information and feels more intentional even if the data is the same. DTOs like you've defined them have a way of become grab bags of data because they don't have a "place" and aren't part of a bigger picture.