Laravel automatically trims incoming strings in the HTTP request. This convenience can be easy to take for granted because it’s such a sensible default behavior, but how would you disable it for just one route? And why might you want to do that?
First, just to be clear, when I say trimming a string, I mean that all leading and trailing whitespace is removed. So if someone types an extra space after their email address in a form, Laravel will trim that value in the request, so that
$request->safe->only(['email']) will be what they typed minus the trailing space, which is what the person intended. It keeps your data tidy, and it does so with no extra developer effort required. The
TrimStrings middleware is in the default set of global middleware when you set up a new Laravel project.
TrimStringsbehavior isn’t tied to request validation. It works fine on
$request->get('email'), but you always validate user input, right?
Interestingly, there is one exception out of the box for this middleware: the
password_confirmation fields. In any request, if someone types leading or trailing spaces into a field named
TrimStrings middleware will leave it untrimmed. This makes sense because it’s possible someone could want a leading or trailing space in their password. This exception is set in a protected array named
$except in the
In my case, I was writing code to handle a webhook sent by Twilio. Part of the webhook payload is a signature verification header. It’s important to validate the header against the received message to make sure the message is authentic. In Twilio’s docs, they specicially mention that you should NOT trim strings for their webhook request payload. If you do, the signature won’t validate and the webhook will be rejected. So, how can I turn off the
TrimStrings middleware for just this one route?
My solution was to use a really helpful extension point on the
TrimStrings middleware called
skipWhen. This static method accepts a closure that should return true or false. If it returns true, the
TrimStrings middleware is skipped for that individual request. Also, the current request is passed into the closure, so you can use that in your logic. In my case, I wanted to just skip it for one particular route, so it was a simple one-liner:
App\Http\Middleware\TrimStrings::skipWhen(fn ($request) => $request->url() === route('api.v2.webhooks.webhook-client-twilio-conversations'));
Place that in the
boot method of your
AppServiceProvider and it works exactly as designed.
Finding this method took a little digging. I didn’t see it in the docs (though I’m thinking I should PR the docs to add it), and I had never used it before. Never underestimate the benefits of a little source diving. If you’d like to hear some alternate solutions I considered, and why I ultimately picked this approach, we recorded a podcast episode on the topic. Check it out if you want to know more.