REST API Implementation Plan - Laravel-DDD CRM System
Overview
This document outlines the comprehensive plan for implementing REST APIs that serve both Single Page Application (SPA) and third-party consumers. The API design follows RESTful principles with Laravel best practices while maintaining clean domain boundaries.
API Strategy & Architecture
Dual-Purpose API Design
Our API will serve both SPA and third-party applications with the following architecture:
┌─────────────────────────────────────────────────────────────┐
│ API Gateway Layer │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────────────────────┐ │
│ │ SPA Routes │ │ Public API Routes │ │
│ │ /spa/api/v1 │ │ /api/v1 │ │
│ │ │ │ │ │
│ │ - Session Auth │ │ - Token Auth │ │
│ │ - CSRF Protected│ │ - Rate Limited │ │
│ │ - Rich Responses│ │ - Standard Responses │ │
│ │ - Eager Loading │ │ - Minimal Payloads │ │
│ └─────────────────┘ └─────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Shared Business Logic │
│ Controllers → Services → Domain │
└─────────────────────────────────────────────────────────────┘Authentication Strategy
SPA Authentication (Session-based):
- Laravel Sanctum stateful authentication
- CSRF protection enabled
- Same-origin policy enforced
- Session cookies for state management
Third-Party API Authentication (Token-based):
- Laravel Sanctum API tokens
- Bearer token authentication
- Scoped permissions per token
- Rate limiting and throttling
API Versioning Strategy
URL Structure
# SPA API (Internal)
https://domain.com/spa/api/v1/{module}/{resource}
# Public API (Third-party)
https://domain.com/api/v1/{module}/{resource}Version Management
- Current Version: v1 (stable)
- Future Versions: v2, v3 (backward compatible when possible)
- Deprecation Policy: 12 months notice for breaking changes
- Header Versioning: Accept version in headers as alternative
Multi-Tenancy API Design
Tenant Resolution
// Middleware will resolve tenant from:
1. Subdomain: tenant1.crm.test
2. Header: X-Tenant-ID: tenant1
3. Token scope: tenant:tenant1Tenant Context
- All API calls automatically scoped to tenant
- No tenant ID in URL paths (security)
- Automatic tenant validation on every request
- Cross-tenant access prevention
API Response Standards
Standard Response Format
Success Response:
{
"success": true,
"data": {
// Resource data or collection
},
"meta": {
"timestamp": "2024-01-15T10:30:00Z",
"version": "v1",
"tenant": "tenant1"
}
}Collection Response:
{
"success": true,
"data": [
// Array of resources
],
"pagination": {
"current_page": 1,
"last_page": 10,
"per_page": 25,
"total": 250,
"from": 1,
"to": 25
},
"meta": {
"timestamp": "2024-01-15T10:30:00Z",
"version": "v1",
"tenant": "tenant1"
}
}Error Response:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The given data was invalid.",
"details": {
"email": ["The email field is required."],
"name": ["The name field must be at least 3 characters."]
}
},
"meta": {
"timestamp": "2024-01-15T10:30:00Z",
"version": "v1",
"tenant": "tenant1"
}
}HTTP Status Codes
- 200 OK: Successful GET, PUT, PATCH
- 201 Created: Successful POST
- 204 No Content: Successful DELETE
- 400 Bad Request: Invalid request format
- 401 Unauthorized: Authentication required
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Resource not found
- 422 Unprocessable Entity: Validation errors
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server error
Module-by-Module API Implementation
1. CRM Module API
Lead Management API
Base Path: /api/v1/crm/leads
Endpoints
GET /api/v1/crm/leads
// Query Parameters
?status=new,qualified
?source=website,referral
?assigned_to=user_id
?score_min=50
?score_max=100
?search=email,name,company
?created_after=2024-01-01
?created_before=2024-12-31
?page=1
?per_page=25
?sort=created_at
?order=desc
?include=assigned_user,activities,customerResponse Example:
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"lead_number": "LEAD000001",
"email": "[email protected]",
"status": "qualified",
"source": "website",
"contact_info": {
"first_name": "John",
"last_name": "Doe",
"company": "Tech Corp",
"job_title": "CTO",
"phone": "+1234567890"
},
"score": {
"total": 85,
"behavioral": 50,
"demographic": 35,
"rating": "hot"
},
"estimated_value": 50000.00,
"currency": "USD",
"assigned_to": {
"id": "user123",
"name": "Jane Smith",
"email": "[email protected]"
},
"tags": ["enterprise", "priority"],
"custom_fields": {
"budget": 100000,
"timeline": "Q2 2024"
},
"qualified_at": "2024-01-10T15:30:00Z",
"last_activity_at": "2024-01-15T09:15:00Z",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-15T09:15:00Z"
}
],
"pagination": {
"current_page": 1,
"last_page": 5,
"per_page": 25,
"total": 125
}
}POST /api/v1/crm/leads
{
"email": "[email protected]",
"source": "website",
"contact_info": {
"first_name": "New",
"last_name": "Lead",
"company": "Example Corp",
"job_title": "Manager",
"phone": "+1234567890"
},
"estimated_value": 25000,
"currency": "USD",
"notes": "Interested in enterprise solution",
"tags": ["website", "demo-requested"],
"custom_fields": {
"industry": "technology",
"company_size": 50
}
}PUT /api/v1/crm/leads/{id}GET /api/v1/crm/leads/{id}DELETE /api/v1/crm/leads/{id}
Lead Actions
POST /api/v1/crm/leads/{id}/qualify
{
"notes": "Met qualification criteria",
"assigned_to": "user123"
}POST /api/v1/crm/leads/{id}/convert
{
"customer_data": {
"name": "Tech Corp",
"type": "business",
"industry": "technology"
},
"create_opportunity": true,
"opportunity_data": {
"name": "Tech Corp - Enterprise License",
"amount": 50000,
"stage": "prospecting"
}
}POST /api/v1/crm/leads/{id}/assign
{
"assigned_to": "user123",
"notify": true
}GET /api/v1/crm/leads/{id}/activitiesPOST /api/v1/crm/leads/{id}/activitiesGET /api/v1/crm/leads/{id}/score-history
Customer Management API
Base Path: /api/v1/crm/customers
Customer Endpoints
GET /api/v1/crm/customersPOST /api/v1/crm/customersGET /api/v1/crm/customers/{id}PUT /api/v1/crm/customers/{id}DELETE /api/v1/crm/customers/{id}
Customer Response Example:
{
"id": "customer123",
"customer_number": "CUST000001",
"name": "Tech Corp",
"email": "[email protected]",
"phone": "+1234567890",
"type": "business",
"status": "active",
"industry": "technology",
"company_size": "large",
"annual_revenue": 5000000,
"website": "https://techcorp.com",
"billing_address": {
"line_1": "123 Tech Street",
"line_2": "Suite 100",
"city": "San Francisco",
"state": "CA",
"postal_code": "94105",
"country": "US"
},
"primary_contact": {
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone": "+1234567890",
"job_title": "CTO"
},
"assigned_account_manager": {
"id": "user123",
"name": "Jane Smith"
},
"lifecycle_stage": "customer",
"lifetime_value": 150000.00,
"acquisition_date": "2024-01-01",
"tags": ["enterprise", "technology"],
"custom_fields": {
"crm_system": "salesforce",
"contract_type": "annual"
}
}Customer Actions
GET /api/v1/crm/customers/{id}/ordersGET /api/v1/crm/customers/{id}/invoicesGET /api/v1/crm/customers/{id}/paymentsGET /api/v1/crm/customers/{id}/activitiesGET /api/v1/crm/customers/{id}/opportunitiesGET /api/v1/crm/customers/{id}/metrics
Opportunity Management API
Base Path: /api/v1/crm/opportunities
Similar structure to leads and customers with opportunity-specific fields and actions.
2. Sales Module API
Order Management API
Base Path: /api/v1/sales/orders
Order Endpoints
GET /api/v1/sales/orders
// Query Parameters
?status=confirmed,processing,shipped
?customer_id=customer123
?date_from=2024-01-01
?date_to=2024-12-31
?amount_min=1000
?amount_max=50000
?include=customer,items,paymentsOrder Response Example:
{
"id": "order123",
"order_number": "ORD000001",
"customer": {
"id": "customer123",
"name": "Tech Corp",
"email": "[email protected]"
},
"status": "confirmed",
"type": "sale",
"order_date": "2024-01-15",
"required_date": "2024-01-30",
"subtotal": 45000.00,
"tax_amount": 4500.00,
"shipping_amount": 500.00,
"discount_amount": 2000.00,
"total_amount": 48000.00,
"currency": "USD",
"payment_terms": "net_30",
"billing_address": {
"line_1": "123 Tech Street",
"city": "San Francisco",
"state": "CA",
"postal_code": "94105",
"country": "US"
},
"items": [
{
"id": "item1",
"product": {
"id": "product123",
"name": "Enterprise License",
"sku": "ENT-LIC-001"
},
"quantity": 10,
"unit_price": 5000.00,
"discount_percentage": 10,
"discount_amount": 5000.00,
"tax_rate": 10,
"tax_amount": 4500.00,
"line_total": 45000.00
}
],
"assigned_to": {
"id": "user123",
"name": "Sales Rep"
}
}Order Actions
POST /api/v1/sales/orders/{id}/confirmPOST /api/v1/sales/orders/{id}/shipPOST /api/v1/sales/orders/{id}/deliverPOST /api/v1/sales/orders/{id}/cancelPOST /api/v1/sales/orders/{id}/return
Invoice Management API
Base Path: /api/v1/sales/invoices
Payment Management API
Base Path: /api/v1/sales/payments
3. Operations Module API
Product Management API
Base Path: /api/v1/operations/products
Inventory Management API
Base Path: /api/v1/operations/inventory
Purchase Order API
Base Path: /api/v1/operations/purchase-orders
4. Finance Module API
Chart of Accounts API
Base Path: /api/v1/finance/chart-of-accounts
Journal Entries API
Base Path: /api/v1/finance/journal-entries
5. HRM Module API
Employee Management API
Base Path: /api/v1/hrm/employees
Time Tracking API
Base Path: /api/v1/hrm/time-entries
Leave Management API
Base Path: /api/v1/hrm/leaves
6. Analytics Module API
Metrics API
Base Path: /api/v1/analytics/metrics
Dashboard API
Base Path: /api/v1/analytics/dashboards
Reports API
Base Path: /api/v1/analytics/reports
API Middleware Stack
Authentication Middleware
// For SPA routes
Route::middleware(['web', 'auth:sanctum'])->group(function () {
// SPA routes
});
// For API routes
Route::middleware(['api', 'auth:sanctum', 'throttle:api'])->group(function () {
// Public API routes
});Tenant Resolution Middleware
class ResolveTenantMiddleware
{
public function handle(Request $request, Closure $next)
{
$tenant = $this->resolveTenant($request);
if (!$tenant) {
return response()->json(['error' => 'Invalid tenant'], 403);
}
// Set tenant context
app()->instance('tenant', $tenant);
return $next($request);
}
private function resolveTenant(Request $request): ?Tenant
{
// Try subdomain first
if ($tenant = $this->getTenantFromSubdomain($request)) {
return $tenant;
}
// Try header
if ($tenant = $this->getTenantFromHeader($request)) {
return $tenant;
}
// Try token scope
if ($tenant = $this->getTenantFromToken($request)) {
return $tenant;
}
return null;
}
}API Response Middleware
class ApiResponseMiddleware
{
public function handle(Request $request, Closure $next)
{
$response = $next($request);
if ($response instanceof JsonResponse) {
$data = $response->getData(true);
$wrappedData = [
'success' => $response->status() < 400,
'data' => $data,
'meta' => [
'timestamp' => now()->toISOString(),
'version' => 'v1',
'tenant' => app('tenant')->slug ?? null,
]
];
$response->setData($wrappedData);
}
return $response;
}
}Rate Limiting
// config/sanctum.php
'api_throttle' => [
'attempts' => 60, // requests per minute
'decay_minutes' => 1,
],
'spa_throttle' => [
'attempts' => 300, // higher limit for SPA
'decay_minutes' => 1,
],Error Handling Strategy
Global Exception Handler
class ApiExceptionHandler extends Handler
{
public function render($request, Exception $exception)
{
if ($request->expectsJson()) {
return $this->handleApiException($request, $exception);
}
return parent::render($request, $exception);
}
protected function handleApiException($request, Exception $exception)
{
$statusCode = 500;
$errorCode = 'INTERNAL_ERROR';
$message = 'An error occurred';
$details = null;
switch (true) {
case $exception instanceof ValidationException:
$statusCode = 422;
$errorCode = 'VALIDATION_ERROR';
$message = 'The given data was invalid.';
$details = $exception->errors();
break;
case $exception instanceof ModelNotFoundException:
$statusCode = 404;
$errorCode = 'RESOURCE_NOT_FOUND';
$message = 'The requested resource was not found.';
break;
case $exception instanceof AuthenticationException:
$statusCode = 401;
$errorCode = 'AUTHENTICATION_REQUIRED';
$message = 'Authentication is required.';
break;
case $exception instanceof AuthorizationException:
$statusCode = 403;
$errorCode = 'INSUFFICIENT_PERMISSIONS';
$message = 'You do not have permission to perform this action.';
break;
case $exception instanceof ThrottleRequestsException:
$statusCode = 429;
$errorCode = 'RATE_LIMIT_EXCEEDED';
$message = 'Too many requests. Please try again later.';
break;
}
return response()->json([
'success' => false,
'error' => [
'code' => $errorCode,
'message' => $message,
'details' => $details,
],
'meta' => [
'timestamp' => now()->toISOString(),
'version' => 'v1',
'tenant' => app('tenant')->slug ?? null,
]
], $statusCode);
}
}API Documentation Strategy
OpenAPI/Swagger Specification
- Generate comprehensive API documentation
- Interactive API explorer
- Code examples for multiple languages
- Authentication flow documentation
Documentation Structure
docs/api/
├── openapi.yaml # Master OpenAPI spec
├── modules/
│ ├── crm.yaml # CRM endpoints
│ ├── sales.yaml # Sales endpoints
│ ├── operations.yaml # Operations endpoints
│ ├── finance.yaml # Finance endpoints
│ ├── hrm.yaml # HRM endpoints
│ └── analytics.yaml # Analytics endpoints
├── authentication.md # Auth documentation
├── rate-limiting.md # Rate limiting info
├── errors.md # Error codes and handling
├── pagination.md # Pagination guidelines
├── filtering.md # Filtering and search
└── webhooks.md # Webhook documentationPerformance Optimization
Caching Strategy
// API Response Caching
Route::middleware(['cache:5'])->group(function () {
// Cacheable endpoints
});
// Query Result Caching
$leads = Cache::remember("leads:tenant:{$tenantId}:filters:{$filtersHash}", 300, function () {
return Lead::with(['assignedUser'])->filtered($filters)->paginate();
});Database Optimization
- Eager loading for relationships
- Database indexes for common queries
- Query optimization for large datasets
- Connection pooling for high concurrency
API Response Optimization
// Conditional field loading
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'activities' => $this->whenLoaded('activities'),
'detailed_stats' => $this->when($request->include_stats, function () {
return $this->calculateDetailedStats();
}),
];
}Security Considerations
API Security Measures
- Authentication: Multi-layer auth with tokens and sessions
- Authorization: Role-based access control
- Rate Limiting: Prevent abuse and DoS attacks
- Input Validation: Comprehensive request validation
- SQL Injection Prevention: Eloquent ORM protection
- XSS Prevention: Output sanitization
- CSRF Protection: For SPA endpoints
- HTTPS Enforcement: SSL/TLS for all endpoints
Data Privacy
- Personal data encryption
- Audit logging for sensitive operations
- GDPR compliance features
- Data retention policies
Testing Strategy
API Testing Levels
- Unit Tests: Individual endpoint logic
- Integration Tests: Database and service integration
- Feature Tests: Complete API workflows
- Performance Tests: Load and stress testing
- Security Tests: Penetration testing
Test Examples
// Feature test example
public function test_can_create_lead_via_api()
{
$user = User::factory()->create();
$this->actingAs($user, 'sanctum');
$response = $this->postJson('/api/v1/crm/leads', [
'email' => '[email protected]',
'source' => 'website',
'contact_info' => [
'first_name' => 'John',
'last_name' => 'Doe',
],
]);
$response->assertStatus(201)
->assertJsonStructure([
'success',
'data' => ['id', 'email', 'status'],
'meta' => ['timestamp', 'version', 'tenant']
]);
}Implementation Phases
Phase 1: Foundation (Weeks 1-2)
- Base API infrastructure
- Authentication and authorization
- Tenant resolution middleware
- Response formatting
- Error handling
Phase 2: Core Modules (Weeks 3-6)
- CRM API endpoints
- Sales API endpoints
- Basic CRUD operations
- Relationship loading
- Validation rules
Phase 3: Advanced Features (Weeks 7-10)
- Operations API endpoints
- Finance API endpoints
- HRM API endpoints
- Complex business operations
- Bulk operations
Phase 4: Analytics & Optimization (Weeks 11-12)
- Analytics API endpoints
- Performance optimization
- Caching implementation
- Load testing
Phase 5: Documentation & Polish (Weeks 13-14)
- API documentation
- Code examples
- Security audit
- Final testing
This comprehensive API implementation plan provides a solid foundation for building both SPA and third-party compatible REST APIs while maintaining clean architecture principles and Laravel best practices.