Laravel is beautiful. Elegant, succinct and beautiful, but luckily this article is not about poetry, else I would have gone on about a man who fell in love with a framework.
A gentle introduction to life, without Form Requests, infact, life without Validators.
Let’s say we have a ProductController that handles specific actions related to a product and returns json.
<?php
namespace App\Http\Controllers;
class ProductController extends Controller
{
/**
* Create A New Product
* @return Response
*/
public function create(Request $request)
{
/**
* What your favorite tech bro would do, before validators
*/
if ($request->get("price") < 0) {
return response()->json([
"status" => "error", "message" =>
"Price cannot be greater than zero"], 406);
}
if (is_null($request->get("shop_id"))) {
return response()->json([
"status" => "error", "message" =>
"shop_id is required"], 406);
}
if (is_null($request->get("name"))) {
return response()->json([
"status" => "error", "message" => "name is required"], 406);
}
$shop = Shop::find($request->get("shop_id"));
if (null == $shop) {
return response()->json([
"status" => "error", "message" =>
"shop_id does not exist"], 406);
}
/**
* Actual action being performed here
*/
$product = Product::create($request->all());
return response()->json([
"status" => "success", "data" => $product->toArray()], 200);
}
}
From the above, we can see that validation takes up the bulk of logic for performing an action. Thankfully we can call the validator on the request object, so the multiple ifs could be refactored as below.
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Validator;
class ProductController extends Controller
{
/**
* Create A Product
* @return Response
*/
public function create(Request $request)
{
$request->validate([
"shop_id" => "required|exists:shops,id",
"name" => "required|string",
"price" => "required|numeric|gt:0"
]);
$product = Product::create($request->validated());
return response()->json([
"status" => "success", "data" => $product->toArray()], 200);
}
}
Validations often take up a bulk of the lines when writing business logic.
Imagine a bar, run by a robot. Each time you order a drink, the robot spends some minutes asking you for an ID to prove you’re of legal drinking age.
Form Requests provide a nice way of encapsulating requirements for processing a given resource, allowing your services do their actual jobs.
Form Requests are the bouncers you put at the entrance to the bar, with one simple instruction: “Don’t let anyone below 18 get in here”. Hence, the robot doesn’t need to know your age. It just serves the drink while the bouncers now have the actual task of checking IDs.
They extend the Illuminate\Foundation\Http\FormRequest class.
To create a Form Request, run the artisan make request command, supplying the request name as an argument. In our instance:
php artisan make:request ProductRequest
This will create a Requests Folder, if you don’t already have one, within your App\Http Folder.
Form Request Structure.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
Form Request come with two methods already included:
authorize: You can use this to handle access permissions for the resource. This method should return a Boolean, indicating to grant access or not. By default, this returns false. Change this to true to grant access to the given resource, or you can also add custom permission checks within this method.
rules: This is where you define validation rules for the request. Your rules should return an array with the request field as a key and the validation rule as value. So in our case:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"shop_id" => "required|exists:shops,id",
"name" => "required|string",
"price" => "required|numeric|gt:0"
];
}
}
Using Your Form Requests.
To use our newly created FormRequest, we just need to type hint our controller method and Laravel will automatically resolve it for us from the service container, by doing so, validating the request.
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ProductRequest;
class ProductController extends Controller
{
/**
* Create A New Product
* @return Response
*/
public function create(ProductRequest $request)
{
$product = Product::create($request->validated());
return response()->json([
"status" => "success", "data" => $product->toArray()], 200);
}
}
Switching Validation Rules based on Request methods.
You can return different rules depending on the request method specified, by switching through each request, this allows you to be able to use the same request for multiple actions. Say we want to update a product, we don’t want to require that the client sends us the name or the price fields.
To achieve this we can switch through the request method:
<?php
...
public function rules()
{
switch ($this->method()) {
case "POST":
return [
"shop_id" => "required|exists:shops",
"name" => "required|string",
"price" => "required|numeric|gt:0"
];
case "PUT":
return [
"shop_id" => "exists:shops",
"name" => "string|nullable",
"price" => "numeric|gt:0"
];
}
}
We can now use the ProductRequest when updating the product:
<?php
...
public function update(Product $product, ProductRequest $request)
{
$product->update($request->validated());
return response()->json([
"status" => "success",
"data" => $product->toArray()], 200);
}
Form Requests provide us with structure to organize requirements for our controller processes. As we can see, so far so good, I can’t think of any reason why you aren’t using Form Requests yet.