IUseCase

This is an interface to a Use Case implementation or otherwise known as a Domain Service

  • Domain services should not hold state (application services are not domain services, they are on the outer layer close to the UI layer, and can hold application/task state)

  • Domain services have very little behavior and only which does not fit cohesively in any domain model

  • Domain services sit in the core domain layer along with entities, value objects, aggregates and domain events, and expose domain models in their interfaces

import { User as UserAggregate } from '@modules/user';
import {
	IUseCase,
	DomainId,
	Result,
	UserNameValueObject,
	ChangesObserver,
	PasswordValueObject,
	EmailValueObject,
	BirthdayValueObject,
} from '@types-ddd';

export interface SignupDto {
	email: string;
	name: string;
	password: string;
	birthDay: Date;
}

export interface IUserRepo {
	exists: ({ email: string }) => Promise<boolean>;
	save: (user: UserAggregate) => Promise<void>;
}

export class SignupUseCase implements IUseCase<SignupDto, Result<void>> {
	constructor(private readonly userRepository: IUserRepo) {}

	async execute(dto: SignupDto): Promise<Result<void>> {
		try {
			const { name, password, email, birthDay } = dto;

			const userAlreadyExists = await this.userRepository.exists({ email });

			if (userAlreadyExists) {
				return Result.fail('User already exists', 'CONFLICT');
			}

			const observer = ChangesObserver.init();

			const nameOrError = UserNameValueObject.create(name);
			const passwordOrError = PasswordValueObject.create(password);
			const emailOrError = EmailValueObject.create(email);
			const birthDayOrError = BirthdayValueObject.create(birthDay);

			observer.add(nameOrError);
			observer.add(passwordOrError);
			observer.add(emailOrError);
			observer.add(birthDayOrError);

			const isAllValueObjectOk = observer.isAllResultsSuccess();
			if (!isAllValueObjectOk) {
				const message = observer.getResult().errorValue();
				return Result.fail(message);
			}

			const userName = nameOrError.getResult();
			const userPassword = passwordOrError.getResult();
			const userEmail = emailOrError.getResult();
			const userBirthDay = birthDayOrError.getResult();

			userPassword.encrypt();

			const userOrError = UserAggregate.create({
				ID: DomainId.create(),
				userName,
				userPassword,
				userEmail,
				userBirthDay,
			});

			if (userOrError.isFailure) {
				const message = userOrError.errorValue();
				return Result.fail(message);
			}

			const user = userOrError.getResult();

			await this.userRepository.save(user);

			return Result.success();
		} catch (err) {
			return Result.fail('Error on SignupUseCase', 'INTERNAL_SERVER_ERROR');
		}
	}
}

Last updated