<< back to Guides

⚡ CQRS Quick Guide

CQRS (Command Query Responsibility Segregation) is a software architecture pattern that separates read operations (queries) from write operations (commands), enabling better scalability, flexibility, and performance for complex systems.


✨ Core Concepts


✅ When to Use CQRS


🧱 Simple Structure

+-----------+           +----------------+
|  Client   |  ----->   |  Command API   |
+-----------+           +----------------+
                             |
                             v
                      Write/Command Model
                             |
                        (Database Write)
                             |
                      Event Store / Bus
                             |
                             v
+-----------+           +----------------+
|  Client   |  <-----   |   Query API    |
+-----------+           +----------------+
                             |
                      Read/Query Database

🛠 Command Example (Write)

POST /users

{
  "name": "Alice",
  "email": "alice@example.com"
}

This goes through validations, domain logic, and emits a UserCreatedEvent.


🔍 Query Example (Read)

GET /users/123

Response:
{
  "id": "123",
  "name": "Alice",
  "email": "alice@example.com"
}

This hits a read-optimized store, possibly denormalized for performance.


🔁 Eventual Consistency

CQRS often uses eventual consistency between the write and read models.


🧩 CQRS vs CRUD

Feature CRUD CQRS
Read/Write Model Shared Separated
Simplicity Simple apps Complex apps
Scaling Less flexible Easier to scale independently
Consistency Strong Often eventual

🔄 Combine with Event Sourcing


🔐 Pros

⚠️ Cons


📦 Common Use Cases


📦 CQRS Implementation Appendix: Laravel & Java


🚀 Laravel CQRS Example

📁 Directory Structure (Simplified)

app/
├── Commands/
│   └── CreateUserCommand.php
├── Handlers/
│   └── CreateUserHandler.php
├── Queries/
│   └── GetUserQuery.php
├── Controllers/
│   └── UserController.php

🧩 CreateUserCommand.php

namespace App\Commands;

class CreateUserCommand
{
    public string $name;
    public string $email;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }
}

🧠 CreateUserHandler.php

namespace App\Handlers;

use App\Commands\CreateUserCommand;
use App\Models\User;

class CreateUserHandler
{
    public function handle(CreateUserCommand $command)
    {
        return User::create([
            'name' => $command->name,
            'email' => $command->email,
        ]);
    }
}

📥 Controller Usage

public function store(Request $request)
{
    $command = new CreateUserCommand($request->name, $request->email);
    $handler = new CreateUserHandler();
    $user = $handler->handle($command);

    return response()->json($user);
}

🔍 GetUserQuery (Simple)

namespace App\Queries;

use App\Models\User;

class GetUserQuery
{
    public static function byId(int $id): ?User
    {
        return User::find($id);
    }
}

☕ Java CQRS Example (Spring Boot)

📁 Project Structure (Simplified)

src/
├── commands/
│   └── CreateUserCommand.java
├── handlers/
│   └── CreateUserHandler.java
├── queries/
│   └── GetUserQuery.java
├── controllers/
│   └── UserController.java

🧩 CreateUserCommand.java

public class CreateUserCommand {
    private String name;
    private String email;

    public CreateUserCommand(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // getters
}

🧠 CreateUserHandler.java

@Service
public class CreateUserHandler {
    private final UserRepository userRepository;

    public CreateUserHandler(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User handle(CreateUserCommand command) {
        User user = new User(command.getName(), command.getEmail());
        return userRepository.save(user);
    }
}

📥 UserController.java

@RestController
@RequestMapping("/users")
public class UserController {
    private final CreateUserHandler createUserHandler;

    public UserController(CreateUserHandler createUserHandler) {
        this.createUserHandler = createUserHandler;
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody CreateUserCommand command) {
        User user = createUserHandler.handle(command);
        return ResponseEntity.ok(user);
    }
}

🔍 GetUserQuery.java

@Service
public class GetUserQuery {
    private final UserRepository userRepository;

    public GetUserQuery(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public Optional<User> byId(Long id) {
        return userRepository.findById(id);
    }
}

<< back to Guides