The Mighty Illuminate Request Object

Published on by

The Mighty Illuminate Request Object image

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:

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
LaraJobs logo

LaraJobs

The official Laravel job board

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit
Supercharge Your SaaS Development with FilamentFlow: The Ultimate Laravel Filament Boilerplate logo

Supercharge Your SaaS Development with FilamentFlow: The Ultimate Laravel Filament Boilerplate

Build your SaaS application in hours. Out-of-the-box multi-tenancy and seamless Stripe integration. Supports subscriptions and one-time purchases, allowing you to focus on building and creating without repetitive setup tasks.

Supercharge Your SaaS Development with FilamentFlow: The Ultimate Laravel Filament Boilerplate
Rector logo

Rector

Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies

Rector
MongoDB logo

MongoDB

Enhance your PHP applications with the powerful integration of MongoDB and Laravel, empowering developers to build applications with ease and efficiency. Support transactional, search, analytics and mobile use cases while using the familiar Eloquent APIs. Discover how MongoDB's flexible, modern database can transform your Laravel applications.

MongoDB

The latest

View all →
Asymmetric Property Visibility in PHP 8.4 image

Asymmetric Property Visibility in PHP 8.4

Read article
Access Laravel Pulse Data as a JSON API image

Access Laravel Pulse Data as a JSON API

Read article
Laravel Forge adds Statamic Integration image

Laravel Forge adds Statamic Integration

Read article
Transform Data into Type-safe DTOs with this PHP Package image

Transform Data into Type-safe DTOs with this PHP Package

Read article
PHPxWorld - The resurgence of PHP meet-ups with Chris Morrell image

PHPxWorld - The resurgence of PHP meet-ups with Chris Morrell

Read article
Herd Executable Support and Pest 3 Mutation Testing in PhpStorm 2024.3 image

Herd Executable Support and Pest 3 Mutation Testing in PhpStorm 2024.3

Read article