Building a Small Laravel Contact Flow
A code-heavy walkthrough of a Laravel contact endpoint with validation, rate limiting, persistence, notifications, and Pest coverage.
This sample post exists to stress-test the article view with real code blocks, headings, links, and paragraphs. It walks through a small Laravel contact flow from route to test.
The route
The route keeps the public surface easy to scan and makes the rate limiter visible.
<?php
use App\Http\Controllers\ContactMessageController;
use Illuminate\Support\Facades\Route;
Route::post("/contact", [ContactMessageController::class, "store"])
->middleware("throttle:contact")
->name("contact.store");The request object
Validation lives in a form request so the controller only receives trusted input.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreContactMessageRequest extends FormRequest
{
public function rules(): array
{
return [
"name" => ["required", "string", "max:120"],
"email" => ["required", "email", "max:160"],
"message" => ["required", "string", "min:20"],
];
}
}The controller
The controller creates the message and sends the notification. The interesting behavior stays explicit.
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreContactMessageRequest;
use App\Models\ContactMessage;
use App\Notifications\ContactMessageReceived;
use Illuminate\Support\Facades\Notification;
class ContactMessageController
{
public function store(StoreContactMessageRequest $request)
{
$message = ContactMessage::create($request->validated());
Notification::route("mail", config("mail.from.address"))
->notify(new ContactMessageReceived($message));
return back()->with("status", "Message sent.");
}
}The test
The feature test protects the behaviour users care about: a valid message is stored, and a notification is sent.
<?php
use App\Models\ContactMessage;
use App\Notifications\ContactMessageReceived;
use Illuminate\Support\Facades\Notification;
use function Pest\Laravel\assertDatabaseHas;
use function Pest\Laravel\post;
it("stores contact messages", function (): void {
Notification::fake();
post(route("contact.store"), [
"name" => "Ada Lovelace",
"email" => "ada@example.com",
"message" => "Could you review the integration boundaries for this API?",
])->assertRedirect()->assertSessionHas("status");
assertDatabaseHas(ContactMessage::class, [
"email" => "ada@example.com",
]);
Notification::assertSentOnDemand(ContactMessageReceived::class);
});That gives the post template a realistic mix of paragraph rhythm, headings, inline links, and long code samples.