I am implementing the Builder pattern in a Node.js (TypeScript) backend to instantiate a Permission object before passing it to my repository layer.I want to reuse this same Builder for both creating and updating a permission, but the presence of the id and the validation rules change completely depending on the action:
When Creating: The id attribute is never sent (the database generates it). Both name and module are strictly mandatory.
When Updating: The id is strictly mandatory. However, name and module become optional, with the condition that at least one of them must be provided (they cannot both be missing). If a field is not provided, it should remain null or undefined so the repository knows it shouldn't overwrite that specific column.
import { CustomError } from "../../../shared";
export class PermissionBuilder {
private name: string = '';
private module: string = '';
constructor() {}
setName(name: string): PermissionBuilder {
if (!name || !name.trim()) throw CustomError.badRequest('Name cannot be empty');
this.name = name;
return this;
}
setModule(module: string): PermissionBuilder {
if (!module || !module.trim()) throw CustomError.badRequest('Module cannot be empty');
this.module = module;
return this;
}
build(): { name: string; module: string } {
return {
name: this.name,
module: this.module,
};
}
}
My questions are:
- Is it considered a good practice to handle this conditional logic (where id is missing for creation but required for partial updates) inside a single Builder, or should I split this into two separate builders (e.g., CreatePermissionBuilder and UpdatePermissionBuilder)?
- If keeping a single Builder is the right approach, how should I restructure the internal state and the build() method to handle a payload that dynamically changes its required fields based on whether an id is present or not?
Top comments (0)