Claude
Skills
Sign in
Back

implement-cqrs-handler

Included with Lifetime
$97 forever

Provides step-by-step implementation guide for creating CQRS command or query handlers following project patterns with ServiceResult, dependency injection, and handler registration. Use when implementing new use cases, adding features, creating API endpoints, or building application layer logic.

Backend & APIsscripts

What this skill does


Works with Python handlers in application/commands/ and application/queries/.
# Implement CQRS Handler

## Purpose
Create command or query handlers following the project's CQRS pattern with proper separation of write (command) and read (query) operations, ServiceResult pattern, and dependency injection.

## When to Use

Use this skill when:
- **Implementing new use cases** - Creating new application layer operations
- **Adding features** - Building new functionality that modifies or queries data
- **Creating API endpoints** - Wiring business logic to interface layer
- **Building application layer logic** - Orchestrating domain services and repositories

**Trigger phrases:**
- "Create a command handler for X"
- "Implement a query to retrieve Y"
- "Add a new use case for Z"
- "Build handler for feature X"

## Quick Start

**Command Handler (writes, returns ServiceResult[None]):**
```python
# src/{{PROJECT_NAME}}/application/commands/my_command.py
from {{PROJECT_NAME}}.application.commands.base import CommandHandler
from {{PROJECT_NAME}}.domain.common import ServiceResult

class MyCommandHandler(CommandHandler[MyCommand]):
    def __init__(self, repository: MyRepository):
        self.repository = repository

    async def handle(self, command: MyCommand) -> ServiceResult[None]:
        # Implementation
        return ServiceResult.ok(None)
```

**Query Handler (reads, returns ServiceResult[TResult]):**
```python
# src/{{PROJECT_NAME}}/application/queries/my_query.py
from {{PROJECT_NAME}}.application.queries.base import QueryHandler
from {{PROJECT_NAME}}.application.dto.my_dto import MyDTO
from {{PROJECT_NAME}}.domain.common import ServiceResult

class MyQueryHandler(QueryHandler[MyQuery, list[MyDTO]]):
    def __init__(self, repository: MyRepository):
        self.repository = repository

    async def handle(self, query: MyQuery) -> ServiceResult[list[MyDTO]]:
        # Implementation
        return ServiceResult.ok(results)
```

## Table of Contents

### Core Sections
- [Purpose](#purpose) - What this skill helps you build
- [Quick Start](#quick-start) - Immediate working examples for commands and queries
- [Instructions](#instructions) - Complete implementation guide
  - [Step 1: Decide Command vs Query](#step-1-decide-command-vs-query) - When to use each pattern
  - [Step 2: Create Request Object](#step-2-create-request-object) - Define command/query data structures
  - [Step 3: Create Handler](#step-3-create-handler) - Implement handler logic with templates
  - [Step 4: Create DTO](#step-4-create-dto-queries-only) - Data transfer objects for queries
  - [Step 5: Register in Container](#step-5-register-in-container) - Dependency injection setup
  - [Step 6: Wire to MCP Tool](#step-6-wire-to-mcp-tool) - Expose handler via MCP interface

### Supporting Resources
- [Templates](templates/) - Handler skeletons and boilerplate code
  - [templates/command_handler.py](templates/command_handler.py) - Command handler skeleton
  - [templates/query_handler.py](templates/query_handler.py) - Query handler skeleton
- [References](references/reference.md) - CQRS pattern deep dive and architecture
- [Requirements](#requirements) - Pattern compliance checklist

### Utility Scripts
- [Generate Handler](./scripts/generate_handler.py) - Auto-generate CQRS handler boilerplate code
- [List Handlers](./scripts/list_handlers.py) - List and inventory all CQRS handlers in the project
- [Validate CQRS Separation](./scripts/validate_cqrs_separation.py) - Validate CQRS pattern separation in handlers

### Related Documentation
- ARCHITECTURE.md - System architecture overview
- CLAUDE.md - Core rules and patterns

## Instructions

### Step 1: Decide Command vs Query

**Use Command when:**
- Writing/modifying data
- Changing system state
- Side effects required
- Examples: IndexFile, DeleteFile, InitializeProject

**Use Query when:**
- Reading data only
- No state changes
- Retrieving information
- Examples: SearchCode, GetStats, FindRelated

### Step 2: Create Request Object

**For Commands:**
```python
# src/{{PROJECT_NAME}}/application/commands/my_command_command.py
from dataclasses import dataclass
from {{PROJECT_NAME}}.application.commands.base import Command

@dataclass
class MyCommand(Command):
    """Command to perform write operation.

    Contains all data needed for the operation.
    """
    param1: str
    param2: int
    force: bool = False
```

**For Queries:**
```python
# src/{{PROJECT_NAME}}/application/queries/my_query.py
from dataclasses import dataclass
from {{PROJECT_NAME}}.application.queries.base import Query

@dataclass
class MyQuery(Query):
    """Query to retrieve data.

    Contains parameters for data retrieval.
    """
    filter_by: str
    limit: int = 10
```

### Step 3: Create Handler

**Command Handler Template:**
```python
from {{PROJECT_NAME}}.application.commands.base import CommandHandler
from {{PROJECT_NAME}}.core.monitoring import get_logger, traced
from {{PROJECT_NAME}}.domain.common import ServiceResult

logger = get_logger(__name__)

class MyCommandHandler(CommandHandler[MyCommand]):
    """Handler for MyCommand.

    Orchestrates the operation using domain services.
    """

    def __init__(
        self,
        repository: MyRepository,
        service: MyService,
    ):
        """Initialize with required dependencies.

        Args:
            repository: Repository for persistence
            service: Service for business logic
        """
        if not repository:
            raise ValueError("Repository required")
        if not service:
            raise ValueError("Service required")
        self.repository = repository
        self.service = service

    @traced
    async def handle(self, command: MyCommand) -> ServiceResult[None]:
        """Execute the command.

        Args:
            command: The command to execute

        Returns:
            ServiceResult indicating success or failure
        """
        try:
            # 1. Validate inputs
            validation = self._validate(command)
            if not validation.success:
                return validation

            # 2. Execute business logic
            result = await self.service.do_work(command.param1)
            if not result.success:
                return ServiceResult.fail(result.error)

            # 3. Persist changes
            save_result = await self.repository.save(result.data)
            if not save_result.success:
                return ServiceResult.fail(f"Save failed: {save_result.error}")

            logger.info(f"Command completed: {command.param1}")
            return ServiceResult.ok(
                None,
                items_processed=1,
                operation="my_command"
            )

        except Exception as e:
            logger.exception(f"Command failed: {str(e)}")
            return ServiceResult.fail(f"Unexpected error: {str(e)}")

    def _validate(self, command: MyCommand) -> ServiceResult[None]:
        """Validate command parameters."""
        if not command.param1:
            return ServiceResult.fail("param1 is required")
        return ServiceResult.ok(None)
```

**Query Handler Template:**
```python
from {{PROJECT_NAME}}.application.queries.base import QueryHandler
from {{PROJECT_NAME}}.application.dto.my_dto import MyDTO
from {{PROJECT_NAME}}.core.monitoring import get_logger, traced
from {{PROJECT_NAME}}.domain.common import ServiceResult

logger = get_logger(__name__)

class MyQueryHandler(QueryHandler[MyQuery, list[MyDTO]]):
    """Handler for MyQuery.

    Retrieves data without modifying system state.
    """

    def __init__(
        self,
        repository: MyRepository,
    ):
        """Initialize with required dependencies.

        Args:
            repository: Repository for data retrieval
        """
        if not repository:
            raise ValueError("Repository required")
        self.repository = repository

    @traced
    async def handle(self, query: MyQuery) -> ServiceResult[

Related in Backend & APIs