Skip to main content

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:

FilePurposeMiddleware
Routes/web.phpWeb routes with sessionsweb
Routes/api.phpStateless API routesapi

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​

MiddlewarePurpose
webSession, cookies, CSRF protection
authRequires authenticated user
2faTwo-factor authentication check
langLocalization
adminAdmin 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\Models\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\Models\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);