Let's assume you are writing a REST Api with a common structure like Controller > Service > Repository > Database. In the database there's a table with a column with a unique constraint:
// Examples with typeorm/typescript
// user.entity.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Unique()
@Column()
email: string;
// Other properties
}
In the updateUser
method you have to check if the user exists and if the user email
is not used by another one.
Which one of the following approaches would it be better?
A) Interrogate the database to check if the user with the given id
exists and do it again to make sure there's not another user with the same email:
// users.service.ts
@Entity()
export class UsersService {
async updateUser(user: UserDTO): Promise<UserDTO> {
const userById = await this.repository.findOne(user.id);
if (!userById) {
throw new Error('User does not exist');
}
const userWithSameEmail = await this.repository.findOne({
where: { id: Not(user.id), email: user.email }
});
if (userWithSameEmail) {
throw new Error('Email already in use');
}
// Handle errors with some interceptor
// Rest of the method
}
}
B) Database calls could lead to performance issues. The orm will anyway throw an error in case of invalid input:
@Entity()
export class UsersService {
async updateUser(user: UserDTO): Promise<UserDTO> {
try {
const updatedUserEntity = await this.repository.update(user);
// Rest of the method
}
catch (e) {
// Handle error
}
}
}
Quick bonus question
Should the service layer be aware about entities and handle operations like receive the updatedUserEntity
from the repository, map it to the DTO and return it to the level above?