The Mighty Illuminate Request Object
Published on by Paul Redmond
When I first used Symfony, the symfony/http-foundation component blew my mind. In my opinion, it is one of the most essential packages supporting modern PHP web applications. The HTTP foundation fills in the gaps from core PHP features, with a friendly object-oriented interface for requests and responses.
Within the Laravel framework, the Illuminate Request and Response objects benefit from the HTTP foundation component through inheritance and provide an excellent API on top of the core classes that is a delight to use.
In this post, let’s explore some of the sugar and useful methods that Laravel provides via the Illuminate Request object!
The Illuminate\Http\Request
class organizes functionality within three traits that we’ll dive into:
-
InteractsWithContentTypes
-
InteractsWithInput
-
InteractsWithFlashData
I am not showing anything new or enlightening, but hopefully, you discover a useful method or two. I hope developers new to the Laravel framework will dive deeper into the source of these important classes, and appreciate the convenience of the Illuminate Request object.
Interacting with Content Types
During the request/response lifecycle, you’ll sometimes need to determine the request’s intent through the Content-Type
HTTP header. Around this header, the InteractsWithContentTypes
gives us plenty of sugar for repetitive things instead of piecing it together via the HTTP foundation request.
Specifically, we can use the following JSON methods to determine if the user is asking for JSON which will all give us a boolean
answer:
$request->wantsJson();$request->expectsJson();$request->isJson();$request->acceptsJson();
First, the isJson() method explicitly checks for /json
and +json
in the Content-Type
header. The `isJson() method is useful to determine if the client is sending JSON.
The difference between isJson()
and wantsJson()
is nuanced: wantsJson()
is concered with the Accept
header when forming a proper response to the request, while isJson()
is used to determine the current request’s format.
Similarly, the expectsJson() method determines if the user reasonably expects a JSON response with the following conditions:
-
true
if the request is an AJAX request, not a PJAX request, and accepts any content type (*/*
) - OR
- defers to
wantsJson()
if the above is not true
Lastly, the acceptsJson() method is useful to determine if application/json
is within the acceptable response types. The acceptsJson()
method uses a more general method in the same trait called accepts()
, which takes a string or array of content types:
$request->accepts(['application/xml', 'text/xml']);
The last method I’d like to mention in this trait is the format()
method, which you can use to determine the format in the expected response (with an optional default):
// Determines the format based on the request// Returns `json` if the format cannot be found// within the acceptable content types$request->format('json');
There are a few other methods you can check out by browsing the source of the InteractsWithContentTypes.php trait.
Interacting with Input
The convenience provided for working with HTTP input is my favorite part of the extended Illuminate Request object. It has tremendous convenience and utility in Laravel applications for boilerplate code you’re likely to write repeatedly.
The workhorse of the InteractsWithInput
trait is the input() method. The method is simple, so I’ll show it to you here before diving into how to use it:
/** * Retrieve an input item from the request. * * @param string|null $key * @param mixed $default * @return mixed */public function input($key = null, $default = null){ return data_get( $this->getInputSource()->all() + $this->query->all(), $key, $default );}
If you look under the hood, the data_get()
helper combined with this method, provides a one-stop-shop to get input from various sources:
- The input ParameterBag
- The Request query
You’d typically use this method to get POST|PUT|PATCH
parameters, and you can even use it to access input from the query string:
$email = $request->input('email');
The main Request
class also leverages the InteractsWithInput
trait’s all() method to provide a shortcut for input:
// Internally calls $request->all() and tries// to get the input from the request$request->email
Another favorite of mine is the only()
method on this trait. Usually, I want to eliminate everything except the data I am trying to access and possibly store:
// variadic arguments via func_get_args()$request->only('email', 'password'); // Or via an array$request->only(['email', 'password']);
I prefer only() to whitelist what I want from the request and avoid unintended data leaking into the app from the client data.
Another useful method is retrieving input as a boolean, which is very helpful in determining if an input is true
or false
:
// Check opt_in for boolean values, with a default of true// Returns true when the input is:// "1", "true", "on", and "yes"$request->boolean('opt_in', true);
This trait has useful methods for working with HTTP headers:
// Get the token from the Authorization header// Removing the "Bearer " prefix if it exists.// i.e., `Authorization: Bearer 1234`, would return 1234.$request->bearerToken(); $request->hasHeader('X-Custom-Header'); $request->header('X-Custom-Header');
These header methods make it convenient to avoid accessing the headers from the underlying Symfony request:
// Equivalent to $request->header('X-Custom-Header');$request->headers->get('X-Custom-Header'); // Equivalent to $request->hasHeader('X-Custom-Header')! is_null($request->headers->get('X-Custom-Header'));
Some other useful helper methods when working with inputs include:
// All input except password$request->except('password'); // See if the request has a key$request->has('age'); // See if the request has any of the following keys$request->hasAny('age', 'height', 'weight'); // Get all the keys of the input and files$request->keys(); // See if the request is missing input$request->missing('age'); // See if the input is a non-empty value$request->filled('age'); // See if any of the following inputs are filled$request->anyFilled('age', 'height', 'weight'); // Get ?id=12345$request->query('id'); // Get an array of all the files on a request$request->allFiles(); // See if the uploaded data contains a file for a given key$request->hasFile('avatar'); // Get a file from the request$request->file('avatar');
Interacting with Flash Data
A common need in server-side applications is storing request data in the session when things like validation errors occur. Flashing the data to the session ensures the user can correct any invalid form inputs, and store any pertinent data from the request for use in the next request and response.
You may be familiar with the old()
helper in Blade files, which populates the input value with the flashed session data from the previous request:
<input type="email" value="{{ old("email") }}" required />
The old()
helper is indeed deferring to the same old()
method in this trait:
function old($key = null, $default = null){ return app('request')->old($key, $default);}
But how do we get data in the session in the first place?
If you’re new to Laravel, flashing session data might seem like magic, because Validation does this automatically. When a validation error occurs, the framework throws a ValidationException
which eventually stores flashed data in the session via the Response via the exception Handler:
/** * Convert a validation exception into a response. * * @param \Illuminate\Http\Request $request * @param \Illuminate\Validation\ValidationException $exception * @return \Illuminate\Http\Response */protected function invalid($request, ValidationException $exception){ return redirect($exception->redirectTo ?? url()->previous()) ->withInput(Arr::except($request->input(), $this->dontFlash)) ->withErrors($exception->errors(), $exception->errorBag);}
Note that $this->dontFlash
importantly ensures the password
and password_confirmation
inputs are not stored in the session.
Most of the time, validators will take care of flashing data to the session, but you can manually flash input to the session via the request object:
// Flashes $request->input() data to the session$request->flash();
To reemphasize, take care when using this method directly to ensure you don’t flash sensitive data to the user’s session. More conservatively, you can use the request object’s flashOnly()
method:
$request->flashOnly('email', 'first_name', 'last_name');
Or the inverse:
$request->flashExcept('password', 'secret_input');
Macros and More
Remember that since the Illuminate Request object inherits the HTTP Foundation Request, you have everything the foundation component has to offer at your fingertips. I’ll link to the component’s documentation below if you want to dive deeper.
Aside from that, you can extend the Request object in applications via macros. Laravel does this with the Request::validate()
method:
Request::macro('validate', function (array $rules, ...$params) { return validator()->validate($this->all(), $rules, ...$params);});
Learn More
I hope this article was helpful to those new to the Laravel framework wanting to discover some useful tools Laravel has built on top of the core HTTP layer of Laravel applications. For those more experienced with Laravel, I hope this article has introduced a few new methods within the Illuminate Request object or inspired you to dive deeper into these classes.
I’d encourage you to check out the following resources to learn more about the request and response objects in Laravel: