Contenuto dal repository con titoli, esempi, codice, tabelle, link e immagini preservati.
Designing NestJS Services
When to use
- Creating new use cases
- Refactoring services that mix HTTP/DB/domain
- Moving from anemic services to OOP
Core rules
- Application services are use-case classes, one per business intent
- Services orchestrate domain + ports, no framework imports (no
@Injectable()in domain) - Return
Result<T,E>from use-cases, don't throw for expected failures - Dependencies injected via constructor
- No HTTP/ORM imports in application services
Reference shape (TypeScript)
Use-Case Class
@Injectable()
export class CreateUserUseCase {
constructor(
@Inject('UserRepository') private readonly repo: UserRepository,
private readonly hasher: PasswordHasher
) {}
async execute(dto: CreateUserDto): Promise<Result<User, AppError>> {
const existing = await this.repo.findByEmail(dto.email);
if (existing) return err(new ConflictError(`User ${dto.email} already exists`));
const user = User.create(dto.id, Email.create(dto.email));
await this.repo.save(user);
return ok(user);
}
}Examples — Do
// Single responsibility use-case
@Injectable()
export class SubmitOrderUseCase {
constructor(
@Inject('OrderRepository') private repo: OrderRepository,
private paymentService: PaymentService
) {}
async execute(orderId: string): Promise<Result<Order, AppError>> { ... }
}Examples — Don't
// ❌ Anemic service with many methods
@Injectable()
export class UserService {
create() { ... }
update() { ... }
delete() { ... }
// Mixed responsibilities
}
// ❌ Framework leaking into application
import { InjectRepository } from '@nestjs/typeorm'; // Should be in infraChecklist
- [ ] Use-cases are single-responsibility classes
- [ ] Return
Result<T,E> - [ ] No framework imports in application layer
- [ ] Dependencies injected via constructor
See reference/service-patterns.md for full patterns.

