Overview
CQRS (Command Query Responsibility Segregation) is a pattern that separates read operations (Queries) from write operations (Commands). This API implements CQRS in the application layer to clearly distinguish between operations that modify state and those that only retrieve data.Core Principle: A method should either change the state of the system (Command) or return data (Query), but never both.
Commands vs Queries
Commands
Write operations that modify system state
- Create, Update, Delete
- Return void or simple acknowledgment
- Can trigger side effects
Queries
Read operations that retrieve data
- Select, Find, Get
- Never modify state
- Return data models
Commands
Commands represent write operations that change the system’s state.Command Structure
Commands are simple data transfer objects that encapsulate the parameters for a write operation:src/main/java/com/example/demo/usuario/application/commands/RegistrarUsuarioCommand.java
Commands use Value Objects (like
ContrasenaVO) to ensure data is validated before reaching the handler.Command Handler
Handlers process commands and execute the business logic:src/main/java/com/example/demo/usuario/application/commands/handlers/RegistrarUsuarioHandler.java
Command Flow
Queries
Queries represent read operations that retrieve data without modifying state.Query Structure
Queries contain the parameters needed to fetch data:src/main/java/com/example/demo/usuario/application/querys/LoginUsuarioQuery.java
Query Handler
Handlers execute read operations:src/main/java/com/example/demo/usuario/application/querys/handlers/LoginUsuarioHandler.java
Query Flow
Controller Integration
Controllers use both command and query handlers to implement API endpoints:src/main/java/com/example/demo/usuario/infrastructure/controllers/UsuarioRestController.java
Notice how POST requests use Commands (write) while GET requests use Queries (read).
Directory Organization
The CQRS pattern is reflected in the project structure:Benefits
Clear Separation of Concerns
Clear Separation of Concerns
Read and write operations are isolated, making code easier to understand and maintain.
Independent Scaling
Independent Scaling
Read and write operations can be scaled independently based on traffic patterns.
Optimized Data Models
Optimized Data Models
Commands and Queries can use different data models optimized for their specific needs.
Better Security
Better Security
Easier to implement security policies (e.g., read-only users can only execute queries).
Event Sourcing Ready
Event Sourcing Ready
CQRS naturally leads to event-driven architectures and event sourcing patterns.
When to Use CQRS
Good Use Cases
- Systems with complex business logic
- Applications with different read/write performance requirements
- Domain-driven design implementations
- Event-sourced systems
Avoid When
- Simple CRUD applications
- Projects with limited team experience
- Systems where read and write models are identical
CQRS Best Practices
Naming Conventions
- Commands: Use imperative verbs (e.g.,
RegistrarUsuarioCommand,ActualizarProductoCommand) - Queries: Use descriptive nouns (e.g.,
LoginUsuarioQuery,ObtenerProductoQuery)
Handler Responsibilities
- One handler per command/query
- Handlers should be thin, delegating to domain services
- Use dependency injection for repositories
Validation
- Commands validate using Value Objects at creation time
- Handlers should assume incoming data is valid
- Business rule validation happens in the domain layer
Advanced: Eventual Consistency
In advanced CQRS implementations, write and read models can be completely separate: This API uses a simplified CQRS approach where commands and queries share the same database but maintain logical separation in the application layer.Related Concepts
Clean Architecture
See how CQRS fits into the application layer
Value Objects
Learn how VOs validate data in Commands