Laravel add additional attributes to request from middleware and access it from elsewhere

Sometimes, you might want to attach additional attributes to the original request that has made to the Laravel application.

For instance, you want to put your own check in the middleware to see if the request has some headers or not, and pass that ‘check’ by attaching it as an additional attribute to the request.

This way you can also prevent duplicating code, where you would repeat the same code (or query) in the middleware and in the controller.

For instance take following. If I want to get a header value like x-customer-email from the api consumer means, I would write the following code.

1. CheckCustomerHeaderMiddleware.php


public function handle($request, Closure $next)
{
    $customerEmailHeader = 'x-customer-email'; //name of the header we are expecting

    if (!$request->headers->has($customerEmailHeader)) { //checking if the header exists in the request

        return response()->json(['error' => "Please set '{$customerEmailHeader}' header to consume this api"], 400);
    }

    $customerEmail = trim($request->header($customerEmailHeader, '')); //get the email from the request

    $account = Account::where(['email' => trim($customerEmail)])->first(); //find the account

	if (!$account->exists()) { //check if the account exists

		return response()->json(['error' => "Acount not exist"]); //return error message if they don't exist
	}

    return $next($request);
}

2. AccountController.php


public function getAccountDetails(Request $request)
{
    $customerEmailHeader = 'x-customer-email'; //name of the header we are expecting

    $customerEmail = trim($request->header($customerEmailHeader, '')); //get the email from the request

    $account = Account::where(['email' => trim($customerEmail)])->first(); //find the account

	return response()->json($account);
}

As you can see, i repeated my code to get the email header value and even performed the fetch query twice to get the account.

This is simply the waste of resources, and might cause issues in the future if we changed the logic in one place and forgot to change it in the other, correct?

Magic of merge method

You can re-factor the above code by calling merge method on the request and passing the $account from the middleware like so.

1. CheckCustomerHeaderMiddleware.php


public function handle($request, Closure $next)
{
    $customerEmailHeader = 'x-customer-email'; //name of the header we are expecting

    if (!$request->headers->has($customerEmailHeader)) { //checking if the header exists in the request

        return response()->json(['error' => "Please set '{$customerEmailHeader}' header to consume this api"], 400);
    }

    $customerEmail = trim($request->header($customerEmailHeader, '')); //get the email from the request

    $account = Account::where(['email' => trim($customerEmail)])->first(); //find the account

	if (!$account->exists()) { //check if the account exists

		return response()->json(['error' => "Acount not exist"]); //return error message if they don't exist
	}

	//attach the `account` attribute onto the request
    $request->merge(['account' => $account]);

    return $next($request);
}

2. AccountController.php


public function getAccountDetails(Request $request)
{
    $account = $request->account; // just get the account from request

	return response()->json($account);
}

The benefit of above is now we only need to execute the single query and pass it onto the request which can be re-utilized elsewhere (in our case a controller).

Get in touch 👋

Feel free to email me about anything. Want some advice? Give some feedback?

You can also reach me around the web: LinkedIn, GitHub, X (formerly Twitter)