Jan 28, 2023
Extending Laravel Maintenance Mode to Support APIs
How to extend Laravel maintenance mode so API clients can bypass downtime with a secret header.
Laravel has a cool console command for enabling a Maintenance Mode. When in Maintenance Mode visitors are shown a simple landing page and are unable to use the application.
You can pass a secret string to the command and then use that secret to bypass Maintenance Mode while you carry out maintenance work.
php artisan down --secret="my-secret"
Visiting https://myapp.com/my-secret in your browser will set a cookie and redirect you back to https://myapp.com/. From now on you can browse the application normally as if it was not in Maintenance Mode. This is all handled out of the box by the PreventRequestsDuringMaintenance middleware.
But what about your API?
Maintenance Mode requires setting a cookie, and if your API is designed to be stateless or the application consuming your API has no easy way to handle the initial cookie request, your API is totally offline during Maintenance Mode.
In most cases this is probably for the best. If you’re running a migration, you don’t want a mobile app communicating through the API for the same reason you don’t want users browsing the site.
Like with the browser, you might still want API access. Maybe you have a separate developer build of your mobile app, or you need the API as part of your maintenance work.
Adding the same ‘secret’ token feature to Maintenance Mode and setting it up to work with your API is an easy tweak and will let you bypass Maintenance Mode with a simple request header.
The middleware is located at app/Http/Middleware/PreventRequestsDuringMaintenance.php. In a fresh Laravel install, the middleware allows you to provide a list of exempted URIs. These URIs remain accessible when Maintenance Mode is active. For example, you could leave your homepage or support page available.
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
class PreventRequestsDuringMaintenance extends Middleware
{
/**
* The URIs that should be reachable while Maintenance Mode is enabled.
*
* @var array<int, string>
*/
protected $except = [
//
];
}
We can override the base class handle method to add an additional check for our API header.
class PreventRequestsDuringMaintenance extends Middleware
{
...
public function handle($request, Closure $next)
{
if (! $this->app->isDownForMaintenance()) {
return $next($request);
}
$data = $this->app->maintenanceMode()->data();
if (isset($data['secret']) && $request->headers->get('Maintenance-Mode') === $data['secret']) {
return $next($request);
}
return parent::handle($request, $next);
}
}
Let’s look at the new handle method step by step:
if (! $this->app->isDownForMaintenance()) {
return $next($request);
}
Exactly like in the base class, if the application is not in Maintenance Mode we should quickly move on.
$data = $this->app->maintenanceMode()->data();
if (isset($data['secret']) && $request->headers->get('Maintenance-Mode') === $data['secret']) {
return $next($request);
}
This is where the work happens. We pull in the secret set via php artisan down --secret="my-secret" and, if one is set, compare it against the current request’s Maintenance-Mode header. If it’s a match, the request is allowed through.
return parent::handle($request, $next);
Lastly, we need to make sure the original behavior still works. So we delegate back to the base middleware, which checks whether the original URL bypass method was used and displays the Maintenance Mode page if it wasn’t, if the Maintenance-Mode header didn’t match, or if no secret was set.
Conclusion
Now we can access our application in Maintenance Mode, both through the browser and via the API when we set a Maintenance-Mode header.
This can also come in handy if you are using Maintenance Mode to demo a project. You can spin up a server in Laravel Forge, install your app, and enable Maintenance Mode. Then you can demo the project in the browser following the Laravel docs, and compile a development build of your app with a Maintenance-Mode header. Your devices keep unrestricted access while external devices stay locked out.
Image Gallery
