typescriptdomain-driven-designvalue-objects

Can a VO make API calls?


In the registering part of an application I am building, I need to apply a logic that states that e-mails have to be unique in the database. Since I am building the frontend, I'd like to know if I can create a VO (value object) that performs an API call to check if the e-mail is unique. The ideia is very simple, I will pass an e-mail string to a class and, in the constructor, I will raise an error if the API says the e-mail is already in use. The point here is that I don't know if a VO should make API calls like that; although I know it does perform validations.

Also, if necessary, I can perform the call to the API in a separate class: a service, but I'd still need to call inside the VO.


Solution

  • For me, the UNIQUE constraint is not a feature that should be implemented in the constructor nor in the domain layer. You'd probably don't want to check the constraint each time you instantiate the VO. The VO constructor (which for me would me private and use factory method to call it inside the instance):

    class Email {
      readonly username: string;
      readonly domain: string;
    
      private constructor(username: string, domain: string) {
        this.username = username;
        this.domain = domain;
      }
    
      static create(address: string) {
        if (!Email.validMailAddress(address)) {
          throw new Error(`The email ${address} is invalid`);
        }
        const [username, domain] = address.split('@');
        return new Email(username, domain);
      }
    
      static validMailAddress(address: string): boolean {
        // check whether the address is valid or not, using RegExpr or something similar
      }
    
      get value(): string {
        return `${this.username}@${this.domain}`;
      }
    }
    
    

    I'd go for implementing this at the sign up use case, adding a method to the repository for returning a list of users that matches certain criteria (e.g. the email).

    Then you can check in the signUp use case if there is already an user with that email, without leaking any infrastructure impl. to the domain layer.

    Another option is to have an infrastructure service (EmailUniquenessValidator) that takes a Email VO as parameter and return based on the the API call, but this has to be checked at the use case too, because you'll need to inject an implementation to this EmailUniquenessValidator. Personally, I'd go for the repository since it seems pretty clean for me.

    Hope this helps.