Sky.Cms.Api.Shared Architecture¶
Overview¶
Sky.Cms.Api.Shared uses a custom CQRS (Command Query Responsibility Segregation) pattern combined with dependency injection to create a clean, testable, and maintainable API architecture.
Design Patterns¶
CQRS Pattern¶
The API separates read and write operations:
- Commands: Operations that modify state (e.g., submitting a contact form)
- Queries: Operations that retrieve data (e.g., validating a CAPTCHA)
- Handlers: Classes that execute commands or queries
- Mediator: Acts as a dispatcher between controllers and handlers
This pattern provides: - Clear separation of concerns - Easier unit testing - Better maintainability as the API grows - Logical organization of business logic
Service Layer Pattern¶
Services encapsulate business logic and external integrations:
- IContactService - Handles contact form processing and CAPTCHA validation
- ICaptchaValidator - Abstract interface for CAPTCHA validation strategies
Dependency Injection¶
All dependencies are registered in ContactApiServiceExtensions.cs, making the code:
- Loosely coupled
- Testable with mock implementations
- Easy to swap implementations (e.g., different CAPTCHA providers)
Directory Structure¶
Sky.Cms.Api.Shared/
├── Controllers/
│ └── ContactApiController.cs # HTTP API endpoints
├── Models/
│ ├── ContactApiConfig.cs # Configuration model
│ ├── ContactFormRequest.cs # Request DTO
│ ├── ContactFormResponse.cs # Response DTO
│ └── CaptchaValidationRequest.cs # Captcha validation DTO
├── Services/
│ ├── ContactService.cs # Business logic for contact form
│ ├── IContactService.cs # Interface
│ ├── ICaptchaValidator.cs # Interface for CAPTCHA
│ └── Captcha/
│ └── NoOpCaptchaValidator.cs # Default no-op implementation
├── Features/
│ ├── ContactForm/
│ │ ├── Submit/
│ │ │ ├── SubmitContactFormCommand.cs # Command
│ │ │ └── SubmitContactFormHandler.cs # Command handler
│ │ └── ValidateCaptcha/
│ │ ├── ValidateCaptchaQuery.cs # Query
│ │ └── ValidateCaptchaHandler.cs # Query handler
│ └── Shared/
│ ├── ICommand.cs # Base command interface
│ ├── ICommandHandler.cs # Base handler interface
│ ├── IQuery.cs # Base query interface
│ ├── IQueryHandler.cs # Base handler interface
│ ├── IMediator.cs # Mediator interface
│ └── CommandResult.cs # Generic result wrapper
└── Extensions/
└── ContactApiServiceExtensions.cs # DI setup and configuration
Request Flow¶
Contact Form Submission¶
1. HTTP POST /_api/contact/submit
↓
2. ContactApiController.Submit()
↓
3. Anti-forgery token validation
↓
4. Model state validation
↓
5. Dispatch SubmitContactFormCommand via IMediator
↓
6. SubmitContactFormHandler.HandleAsync()
↓
7. ContactService.SubmitContactFormAsync()
├─→ Build email content
├─→ Send via ICosmosEmailSender
└─→ Return result
↓
8. HTTP Response
CAPTCHA Validation¶
1. Client requests CAPTCHA token validation
↓
2. Dispatch ValidateCaptchaQuery via IMediator
↓
3. ValidateCaptchaHandler.HandleAsync()
↓
4. ContactService.ValidateCaptchaAsync()
├─→ Check configuration
├─→ Route to appropriate provider (Turnstile or reCAPTCHA)
└─→ Return validation result
Key Components¶
ContactApiController¶
- Exposes HTTP endpoints
- Handles anti-forgery token management
- Coordinates CQRS dispatch
- Returns standardized responses
ContactService¶
- Implements core business logic
- Integrates with email service (ICosmosEmailSender)
- Supports multiple CAPTCHA providers
- Includes comprehensive error handling
Feature Handlers¶
- SubmitContactFormHandler: Processes contact form submissions
- ValidateCaptchaHandler: Validates CAPTCHA tokens
Extensibility¶
Adding new endpoints is straightforward:
- Create a new feature folder:
Features/YourFeature/ - Define command/query:
YourCommand.csorYourQuery.cs - Implement handler:
YourHandler.cs - Create service interface and implementation if needed
- Register in
ContactApiServiceExtensions.cs - Add controller method in
ContactApiController.cs(or new controller)
Configuration-Driven Behavior¶
The API uses configuration (via ContactApiConfig) to control behavior:
- CAPTCHA Provider: Auto-detected from configuration
- Email Target: Configurable admin email
- Message Length: Configurable via MaxMessageLength
- Rate Limiting: Per-IP rate limit configuration
This makes the API flexible without code changes.
Security Features¶
- Anti-forgery Protection: Token validation on POST requests
- Rate Limiting: 5 requests per minute per IP address
- CAPTCHA Validation: Optional but recommended in production
- Input Validation: Strict model validation on all DTOs
- Email Validation: RFC 5322 compliant email validation
- Error Masking: Generic error messages to prevent information disclosure
Error Handling¶
Errors are handled at multiple levels: 1. Controller level: Invalid model state, framework errors 2. Handler level: Validation and processing errors 3. Service level: External API failures, email sending failures
All errors are logged with contextual information (IP address, email, etc.) for debugging.
Logging¶
Comprehensive logging is implemented using standard ILogger<T>:
- Information: Successful operations
- Warning: Validation failures, external API issues
- Error: Service failures, exceptions
Access logs include: - Submitted email address - Remote IP address - Timestamp - Operation status - Error details (when applicable)