-
You run the In my case I have some additional getters which are not part of the EntityProps and are available only on the built instance of Entity. This means I have to validate after instantiating. Is this a good approach? I am using a zod schema to run the validation. The same goes for any nested entities inside the Aggregate. For example here I am also mapping the export class InvoiceEntity extends AggregateRoot<InvoiceProps> {
static create(props: InvoiceProps): InvoiceEntity {
const id = randomUUID()
const invoice = new InvoiceEntity({
id,
props: {
...props,
lines: props.lines.map(LineItemEntity.create),
},
})
invoice.validate()
return invoice
}
public validate(): void {
invoiceSchema.parse(this)
}
get invoiceNumber() {
return this.props.invoiceNumber
}
// ... more getters
} |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 5 replies
-
You can validate in any place in the entity where it's needed. Any method can validate. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the quick reply! The input is validated in the controller via DTOs as well. IMO, validating input in the domain as well will help if someone removes/breaks the DTO layer validation. Regarding nested entities inside the AggregateRoot (e.g. |
Beta Was this translation helpful? Give feedback.
-
You can instantiate directly in the props like in your example, works fine if you just need to construct an object without doing anything else. Though if you need to execute some logic, for example check invariant that involves all line items, you can create a method that updates line items and use that method instead. Method is also nice to have if you need to reuse it in other places, so you don't have to repeat code for setting line items. |
Beta Was this translation helpful? Give feedback.
-
I wanted to clarify another aspect to getters in Entities. As mentioned in previous comments, the My initial thought is to extend/override the base const result = {
id: this._id,
createdAt: this._createdAt,
updatedAt: this._updatedAt,
...this.props,
total: this.total,
someOtherGetter: this.someOtherGetter,
// etc.
};
return Object.freeze(result); What is your suggestion on this? |
Beta Was this translation helpful? Give feedback.
You can validate in any place in the entity where it's needed. Any method can validate.
Though, for typical sanity validation (like string/number validation with Zod), I would do it only on the edge of the application where it receives external data (like input DTOs in the controller, or if you query data from external APIs). Invalid data shouldn't go any further from outer layers and shouldn't get to the domain.
In the domain we usually consider that data is already validated by the upper layers, and only validate in some rare cases where we need extra safety, or we only validate business rules (invariants), not the input sanity.
Though, if you absolutely want this extra safety, it's fin…