Routes & Controllers
Routes define the URLs your addon responds to, while controllers handle the logic for those requests. This guide covers routing patterns and controller best practices.
Route Files
Addons have two main route files:
| File | Purpose | Middleware |
|---|---|---|
Routes/web.php | Web routes with sessions | web |
Routes/api.php | Stateless API routes | api |
Basic Web Routes
Simple Routes
// Routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use Addons\EmailValidator\Http\Controllers\ValidatorController;
Route::middleware(['web', 'auth'])->prefix('email-validator')->group(function () {
// Basic routes
Route::get('/', [ValidatorController::class, 'index'])
->name('emailvalidator.index');
Route::get('/validate', [ValidatorController::class, 'showValidateForm'])
->name('emailvalidator.validate.form');
Route::post('/validate', [ValidatorController::class, 'validate'])
->name('emailvalidator.validate');
Route::get('/history', [ValidatorController::class, 'history'])
->name('emailvalidator.history');
Route::get('/settings', [ValidatorController::class, 'settings'])
->name('emailvalidator.settings');
Route::post('/settings', [ValidatorController::class, 'saveSettings'])
->name('emailvalidator.settings.save');
});
Resource Routes
For CRUD operations, use resource routes:
use Addons\EmailValidator\Http\Controllers\RuleController;
Route::middleware(['web', 'auth'])->prefix('email-validator')->group(function () {
// Creates: index, create, store, show, edit, update, destroy
Route::resource('rules', RuleController::class)
->names([
'index' => 'emailvalidator.rules.index',
'create' => 'emailvalidator.rules.create',
'store' => 'emailvalidator.rules.store',
'show' => 'emailvalidator.rules.show',
'edit' => 'emailvalidator.rules.edit',
'update' => 'emailvalidator.rules.update',
'destroy' => 'emailvalidator.rules.destroy',
]);
});
Route Parameters
// Single parameter
Route::get('/result/{id}', [ValidatorController::class, 'showResult'])
->name('emailvalidator.result');
// Multiple parameters
Route::get('/history/{year}/{month}', [ValidatorController::class, 'historyByMonth'])
->name('emailvalidator.history.month');
// Optional parameters
Route::get('/export/{format?}', [ValidatorController::class, 'export'])
->name('emailvalidator.export');
// Parameter constraints
Route::get('/result/{id}', [ValidatorController::class, 'showResult'])
->where('id', '[0-9]+')
->name('emailvalidator.result');
API Routes
RESTful API
// Routes/api.php
<?php
use Illuminate\Support\Facades\Route;
use Addons\EmailValidator\Http\Controllers\Api\ValidatorApiController;
Route::middleware(['api', 'auth:api'])->prefix('email-validator')->group(function () {
// Validate single email
Route::post('/validate', [ValidatorApiController::class, 'validate']);
// Batch validation
Route::post('/validate/batch', [ValidatorApiController::class, 'validateBatch']);
// Get validation result
Route::get('/result/{id}', [ValidatorApiController::class, 'getResult']);
// List validation history
Route::get('/history', [ValidatorApiController::class, 'history']);
// Webhook endpoints (no auth)
Route::post('/webhook/callback', [ValidatorApiController::class, 'webhookCallback'])
->withoutMiddleware(['auth:api']);
});
API Versioning
Route::middleware(['api', 'auth:api'])->prefix('v1/email-validator')->group(function () {
Route::post('/validate', [ValidatorApiController::class, 'validate']);
});
Route::middleware(['api', 'auth:api'])->prefix('v2/email-validator')->group(function () {
Route::post('/validate', [ValidatorApiV2Controller::class, 'validate']);
});
Middleware
Available Middleware
| Middleware | Purpose |
|---|---|
web | Session, cookies, CSRF protection |
auth | Requires authenticated user |
2fa | Two-factor authentication check |
lang | Localization |
admin | Admin role required |
Applying Middleware
// Group middleware
Route::middleware(['web', 'auth', '2fa'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
// Single route middleware
Route::get('/admin-only', [AdminController::class, 'index'])
->middleware(['auth', 'admin']);
// Controller middleware (in constructor)
public function __construct()
{
$this->middleware(['auth', '2fa']);
$this->middleware('admin')->only(['destroy', 'forceDelete']);
}
Custom Middleware
Create addon-specific middleware:
// Http/Middleware/CheckQuota.php
namespace Addons\EmailValidator\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckQuota
{
public function handle(Request $request, Closure $next)
{
$user = auth()->user();
$dailyLimit = $user->package->email_validation_limit ?? 100;
$usedToday = $this->getTodayUsage($user->id);
if ($usedToday >= $dailyLimit) {
return response()->json([
'error' => 'Daily validation quota exceeded',
'limit' => $dailyLimit,
'used' => $usedToday
], 429);
}
return $next($request);
}
private function getTodayUsage(int $userId): int
{
// Query usage from database
}
}
Register in service provider:
public function boot(): void
{
$this->app['router']->aliasMiddleware(
'check.quota',
\Addons\EmailValidator\Http\Middleware\CheckQuota::class
);
}
Use in routes:
Route::middleware(['auth', 'check.quota'])->group(function () {
Route::post('/validate', [ValidatorController::class, 'validate']);
});
Controllers
Basic Controller
// Http/Controllers/ValidatorController.php
<?php
namespace Addons\EmailValidator\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Addons\EmailValidator\Entities\ValidationResult;
class ValidatorController extends Controller
{
public function __construct()
{
$this->middleware(['auth', '2fa']);
}
public function index()
{
$stats = [
'total_validated' => ValidationResult::where('user_id', auth()->id())->count(),
'valid_emails' => ValidationResult::where('user_id', auth()->id())
->where('status', 'valid')->count(),
'invalid_emails' => ValidationResult::where('user_id', auth()->id())
->where('status', 'invalid')->count(),
];
return view('emailvalidator::index', compact('stats'));
}
public function showValidateForm()
{
return view('emailvalidator::validate');
}
public function validate(Request $request)
{
$request->validate([
'emails' => 'required|string',
]);
$emails = array_filter(
array_map('trim', explode("\n", $request->emails))
);
// Process validation
$results = $this->processValidation($emails);
return view('emailvalidator::results', compact('results'));
}
public function history()
{
$results = ValidationResult::where('user_id', auth()->id())
->orderBy('created_at', 'desc')
->paginate(50);
return view('emailvalidator::history', compact('results'));
}
private function processValidation(array $emails): array
{
// Validation logic
}
}
Resource Controller
// Http/Controllers/RuleController.php
<?php
namespace Addons\EmailValidator\Http\Controllers;
use App\Http\Controllers\Controller;
use Addons\EmailValidator\Entities\ValidationRule;
use Addons\EmailValidator\Http\Requests\StoreRuleRequest;
use Addons\EmailValidator\Http\Requests\UpdateRuleRequest;
class RuleController extends Controller
{
public function index()
{
$rules = ValidationRule::where('user_id', auth()->id())
->orderBy('priority')
->get();
return view('emailvalidator::rules.index', compact('rules'));
}
public function create()
{
return view('emailvalidator::rules.create');
}
public function store(StoreRuleRequest $request)
{
ValidationRule::create([
'user_id' => auth()->id(),
'name' => $request->name,
'pattern' => $request->pattern,
'action' => $request->action,
'priority' => $request->priority ?? 0,
]);
return redirect()
->route('emailvalidator.rules.index')
->with('success', 'Rule created successfully');
}
public function show(ValidationRule $rule)
{
$this->authorize('view', $rule);
return view('emailvalidator::rules.show', compact('rule'));
}
public function edit(ValidationRule $rule)
{
$this->authorize('update', $rule);
return view('emailvalidator::rules.edit', compact('rule'));
}
public function update(UpdateRuleRequest $request, ValidationRule $rule)
{
$this->authorize('update', $rule);
$rule->update($request->validated());
return redirect()
->route('emailvalidator.rules.index')
->with('success', 'Rule updated successfully');
}
public function destroy(ValidationRule $rule)
{
$this->authorize('delete', $rule);
$rule->delete();
return redirect()
->route('emailvalidator.rules.index')
->with('success', 'Rule deleted successfully');
}
}
API Controller
// Http/Controllers/Api/ValidatorApiController.php
<?php
namespace Addons\EmailValidator\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class ValidatorApiController extends Controller
{
public function validate(Request $request): JsonResponse
{
$request->validate([
'email' => 'required|email',
]);
$result = $this->validateEmail($request->email);
return response()->json([
'success' => true,
'data' => $result
]);
}
public function validateBatch(Request $request): JsonResponse
{
$request->validate([
'emails' => 'required|array|max:100',
'emails.*' => 'required|email',
]);
$results = [];
foreach ($request->emails as $email) {
$results[] = $this->validateEmail($email);
}
return response()->json([
'success' => true,
'data' => $results,
'total' => count($results)
]);
}
public function getResult(int $id): JsonResponse
{
$result = ValidationResult::where('id', $id)
->where('user_id', auth()->id())
->firstOrFail();
return response()->json([
'success' => true,
'data' => $result
]);
}
public function history(Request $request): JsonResponse
{
$results = ValidationResult::where('user_id', auth()->id())
->orderBy('created_at', 'desc')
->paginate($request->per_page ?? 20);
return response()->json([
'success' => true,
'data' => $results->items(),
'meta' => [
'current_page' => $results->currentPage(),
'last_page' => $results->lastPage(),
'per_page' => $results->perPage(),
'total' => $results->total(),
]
]);
}
private function validateEmail(string $email): array
{
// Validation logic
}
}
Form Requests
Use form requests for validation:
// Http/Requests/StoreRuleRequest.php
<?php
namespace Addons\EmailValidator\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreRuleRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->check();
}
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'pattern' => 'required|string|max:500',
'action' => 'required|in:accept,reject,flag',
'priority' => 'nullable|integer|min:0|max:100',
];
}
public function messages(): array
{
return [
'name.required' => 'Please provide a name for this rule',
'pattern.required' => 'A regex pattern is required',
'action.in' => 'Invalid action selected',
];
}
}
Route Service Provider
The RouteServiceProvider loads your route files:
// Providers/RouteServiceProvider.php
<?php
namespace Addons\EmailValidator\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
protected string $moduleNamespace = 'Addons\EmailValidator\Http\Controllers';
public function boot(): void
{
parent::boot();
}
public function map(): void
{
$this->mapWebRoutes();
$this->mapApiRoutes();
}
protected function mapWebRoutes(): void
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('EmailValidator', '/Routes/web.php'));
}
protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace . '\Api')
->group(module_path('EmailValidator', '/Routes/api.php'));
}
}
Role-Based Routing
Load different routes based on user role:
protected function mapWebRoutes(): void
{
Route::middleware('web')->group(function () {
// Common routes for all authenticated users
Route::middleware('auth')
->namespace($this->moduleNamespace)
->group(module_path('EmailValidator', '/Routes/common.php'));
// Admin-only routes
if ($this->isAdmin()) {
Route::middleware(['auth', 'admin'])
->namespace($this->moduleNamespace)
->group(module_path('EmailValidator', '/Routes/admin.php'));
}
// Client routes
if ($this->isClient()) {
Route::middleware(['auth'])
->namespace($this->moduleNamespace)
->group(module_path('EmailValidator', '/Routes/client.php'));
}
});
}
private function isAdmin(): bool
{
if (!auth()->check()) return false;
return auth()->user()->role_id === 1;
}
private function isClient(): bool
{
if (!auth()->check()) return false;
return auth()->user()->is_client === 1;
}
Best Practices
Route Naming
Use consistent, namespaced route names:
// Good
Route::get('/settings', ...)->name('emailvalidator.settings');
Route::get('/rules/{rule}', ...)->name('emailvalidator.rules.show');
// Bad
Route::get('/settings', ...)->name('settings');
Route::get('/rules/{rule}', ...)->name('showRule');
Controller Organization
- One controller per resource or feature area
- Keep controllers thin - move logic to services
- Use form requests for validation
- Use policies for authorization
Response Consistency
For API responses, use a consistent format:
// Success
return response()->json([
'success' => true,
'data' => $result,
'message' => 'Operation completed'
]);
// Error
return response()->json([
'success' => false,
'error' => 'Validation failed',
'errors' => $validator->errors()
], 422);