| name | creating-usecase |
| description | Scaffolds a UseCase protocol and implementation following Clean Architecture. Use when creating a new UseCase. |
Create UseCase
Scaffolds a UseCase protocol and implementation following docs/PATTERNS.md.
File Naming
{Action}{Entity}UseCase.swift → placed in {App}/Domain/UseCases/{Feature}/
Examples:
GetProductListUseCase.swift
AddToCartUseCase.swift
RecordProductInteractionUseCase.swift
Template
protocol {Action}{Entity}UseCaseProtocol {
func execute(input: InputType) async throws -> OutputType
}
final class {Action}{Entity}UseCase: {Action}{Entity}UseCaseProtocol {
private let repository: {Entity}RepositoryProtocol
init(repository: {Entity}RepositoryProtocol) {
self.repository = repository
}
func execute(input: InputType) async throws -> OutputType {
return try await repository.fetchSomething(input: input)
}
}
Patterns
Single Responsibility
Each UseCase does exactly one thing. Name it as {Verb}{Noun}UseCase:
GetProductDetail — fetches product detail
AddToCart — adds item to cart
TrackCheckoutEvents — sends checkout analytics
Protocol-Based
- Always define a protocol (
{Name}UseCaseProtocol) for testability.
- Implementation is a
final class.
- Protocol method is named
execute() by convention.
Constructor Injection
- Inject repository (or other UseCases) via
init.
- Dependencies are always protocol types.
Method Signatures
- Use
async throws for operations that can fail.
- Use
async for operations that cannot fail.
- Input/output use Domain types only (never API response types).
func execute() async throws -> [Product]
func execute(productId: String) async throws -> ProductDetail
func execute(event: TrackingEvent) async
func execute(input: CheckoutInput) async throws -> OrderConfirmation
Error Handling
- Let errors propagate to the ViewModel (do not catch internally unless transforming).
- Use domain-specific error types when needed.
DI Registration
Register in the appropriate assembly file (typically AppUsecasesAssembly.swift):
container.register({Action}{Entity}UseCaseProtocol.self) { resolver in
let repository = resolver.resolve({Entity}RepositoryProtocol.self)!
return {Action}{Entity}UseCase(repository: repository)
}
Checklist
Reference
See docs/PATTERNS.md for the canonical UseCase pattern.
See {App}/Domain/UseCases/ for existing implementations.