2

I'm new to DDD and I trying to create an API using DDD concepts for study purposes. Today, I faced a scenario where I've to create an Application Service to expose a functionality to be cosumed from the external world. The scenario that I came across is to consult in the repository some Domain Entity informations by its id and if the Entity does not exists it should throw a Domain Error to the client, informing that the Entity does not exists. Therefore, my questions are:

  • Should I throw Domain Errors in Application Services?
  • Should this scenario be converted to a Domain Service that is called by the Application service, where the Domain Service treats the repository's response and throws the Error? If yes, how can I nominate this service?

My code looks like this:

import { CostumerRepository } from '@/main/com/acme/sales/domain/repositories';
import { CostumerNotFound } from '@/main/com/acme/sales/domain/errors';
import { GetCostumerHistoryInputDTO } from './dtos/inputs';
import { CostumerHistoryOutputDTO } from './dtos/output';

export class GetCostumerHistory {
  constructor(private readonly costumerRepository: CostumerRepository) {}

  execute(input: GetCostumerHistoryInputDTO): CostumerHistoryOutputDTO {
    const costumer = this.costumerRepository.getById(input.costumerId);

    if (costumer == null) throw new CostumerNotFound();

    return new CostumerHistoryOutputDTO({ costumer });
  }
}
1
  • If this is the actual code you are dealing with, I would challenge you to consider whether throwing an exception here is even desirable. Generally, you should not use exceptions for flow control. Returning nil might be easier for callers to handle than throwing an exception. Dec 8, 2022 at 20:37

1 Answer 1

1

Should this scenario be converted to a Domain Service that is called by the Application service, where the Domain Service treats the repository's response and throws the Error?

Yes, this is probably the better path to take.

In Domain-Driven Design, the responsibility of throwing Domain Errors should be delegated to the Domain layer; This knowledge comes from the Domain after all. So it would be better to implement the logic of checking if the Entity exists in a Domain Service and throw the Domain Error from there.

If yes, how can I nominate this service?

Here's an example of how you could refactor your code to delegate the error handling to a Domain Service:

import { CustomerRepository } from '@/main/com/acme/sales/domain/repositories';
import { CustomerNotFound } from '@/main/com/acme/sales/domain/errors';
import { GetCustomerService } from '@/main/com/acme/sales/domain/services';
import { GetCustomerHistoryInputDTO } from './dtos/inputs';
import { CustomerHistoryOutputDTO } from './dtos/output';

export class GetCustomerHistory {
  constructor(
    private readonly customerRepository: CustomerRepository,
    private readonly getCustomerService: GetCustomerService,
  ) {}

  execute(input: GetCustomerHistoryInputDTO): CustomerHistoryOutputDTO {
    const customer = this.getCustomerService.getById(input.customerId);
    return new CustomerHistoryOutputDTO({ customer });
  }
}
import { CustomerRepository } from '@/main/com/acme/sales/domain/repositories';
import { CustomerNotFound } from '@/main/com/acme/sales/domain/errors';

export class GetCustomerService {
  constructor(private readonly customerRepository: CustomerRepository) {}

  getById(id: string): Customer {
    const customer = this.customerRepository.getById(id);
    if (customer == null) throw new CustomerNotFound();
    return customer;
  }
}

The GetCustomerHistory class is an Application Service that provides the external API for retrieving a customer's history. It relies on the GetCustomerService class, which is a Domain Service responsible for retrieving a customer by their id and throwing the CustomerNotFound error if the customer does not exist.

Hope this helps!

1
  • 1
    Thanks for your answer! I was struggling about the domain service name bc I thought it did not represent/encapsulate a Domain Rule, but your answer clarified to me that the service is part of the Ubiquitous Language from my domain. Dec 8, 2022 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.