My First Pull Request to Laravel Framework — Part 2

Series - My First Pull Request to Laravel Framework

Check this article on Medium: @ngodingbang/my-first-pull-request-to-laravel-framework-part-2-888d06ed86f3

You may want to read this article in Bahasa Indonesia version: Pull Request Pertama Saya di Laravel Framework — Part 2

My Pull Request on Laravel Framework marked in red box, released at 11 May 2022 on 9.12 version (Sumber: https://laravel-news.com/laravel-9-12-0)
My Pull Request on Laravel Framework marked in red box, released at 11 May 2022 on 9.12 version (Sumber: https://laravel-news.com/laravel-9-12-0)

What Exactly Was the Bug I Found?

Basically, I’m trying to add a request header when sending an HTTP Request using the HTTP Client feature in Laravel. But using the withHeaders() method to add a request header in this case is impossible because I need to add the request header in a dynamic way that relies on the URL address of the HTTP Request underlying with.

Source: https://laravel.com/docs/9.x/http-client#headers
Source: https://laravel.com/docs/9.x/http-client#headers

So I decided to use the provided beforeSending() method and added the request header by creating a callback as the code shown below.

This is the code I made to add a request header to the HTTP Client dynamically based on the destination URL. The URL address is obtained from the Illuminate\Http\Client\Request $request parameter given by the Http::beforeSending() method and is processed and stored in the $requestLine variable.
This is the code I made to add a request header to the HTTP Client dynamically based on the destination URL. The URL address is obtained from the Illuminate\Http\Client\Request $request parameter given by the Http::beforeSending() method and is processed and stored in the $requestLine variable.

I can’t use the withHeaders() method of the Illuminate\Http\Client\PendingRequest $pendingRequest parameter to add any new request header.

php

$pendingRequest->withHeaders([‘Authorization’ => ‘Bearer .$requestLine]);

This things happened because the $pendingRequest parameter is already instantiated before HTTP::beforeSending() method is called, so using withHeader() method in the $pendingRequest parameter is useless. The only way to add the wanted request header into the HTTP Client above is to use the withHeader() method provided by the Illuminate\Http\Client\Request $request parameter.

php

$request->toPsrRequest()->withHeader(‘Authorization’, ‘Bearer .$requestLine);

When we use HTTP::beforeSending(), what actually happens is that the previously created callback will be registered into the property in the PendingRequest class as follows.

The callback to add the previous request header will be added to the object in the PendingRequest class. Precisely on the array-type property $beforeSendingCallbacks of the Pending Request class.
The callback to add the previous request header will be added to the object in the PendingRequest class. Precisely on the array-type property $beforeSendingCallbacks of the Pending Request class.

Then all of the registered callbacks will be executed using the PendingRequest class’s runBeforeSendingCallbacks() method as follows.

The previous source code in the PendingRequest class before I create the pull request. This is the bug that I mentioned in the previous chapter.
The previous source code in the PendingRequest class before I create the pull request. This is the bug that I mentioned in the previous chapter.

This is where the problem starts to happen. When using the above method, the request header does not change at all. I keep trying with the code I created, but it still does not give me any significant changes. The request header that I added in the previous callback is still not being sent to the HTTP Client.

Look at the red square I mark here. The headers and headerNames properties of the GuzzleHttp\Psr7\Request object have not changed even though the new “Authorization” request header has been added.
Look at the red square I mark here. The headers and headerNames properties of the GuzzleHttp\Psr7\Request object have not changed even though the new “Authorization” request header has been added.

Then How Do I Solve The Bug?

Yang ingin saya lakukan pada laptop saya ketika bug tersebut tidak kunjung tuntas. Kesal sekali rasanya waktu itu 😤.
Yang ingin saya lakukan pada laptop saya ketika bug tersebut tidak kunjung tuntas. Kesal sekali rasanya waktu itu 😤.

At first I did not understand why this could happen. But after digging further, I finally found where this problem begins. It turns out that the runBeforeSendingCallbacks() method in the PendingRequest class that is used to run HTTP::beforeSending() doesn’t work as expected. Finally I tried to tweak the code in the PendingRequest class as follows.

Source code in the PendingRequest class after I create the pull request. I will explain the details below.
Source code in the PendingRequest class after I create the pull request. I will explain the details below.

So from these tweaks, there are some changes that I made:

  1. @return of the method I changed from \Closure to \GuzzleHttp\Psr7\RequestInterface. This doesn’t actually have a direct impact on the code, but it’s clear from the documentation point of view that @return’s data type is incorrect. Because the tap() method used to modify the $request variable should return the $request itself which is \GuzzleHttp\Psr7\RequestInterface (More explanation can be read here: @taylorotwell/tap-tap-tap-1fc6fc1f93a6).
  2. I created a new variable $callbackResult to capture the result of the pre-existing call_user_func() method. So if there is a return value given from the execution of the call_user_func() method, then the return value will be assigned to the $request variable.
  3. Then I changed the $request variable in the tap() and each() method to pass by reference so that the changes made by $callbackResult can be passed to the return value of the runBeforeSendingCallbacks() method itself.

From these changes, the request header that I added to the previous callback can finally be sent to the HTTP Client as I wanted. Of course there is a slight adjustment to the callback that is in Http::beforeSending() as follows.

This is the code to add request headers to HTTP Client dynamically after adjustment. There is the addition of the keyword “return” at the end of the callback so that the modified $request can be passed to the $callbackResult belonging to the PendingRequest class.
This is the code to add request headers to HTTP Client dynamically after adjustment. There is the addition of the keyword “return” at the end of the callback so that the modified $request can be passed to the $callbackResult belonging to the PendingRequest class.
The new request header “Authorization” has finally been successfully added to the headers and headerNames properties of the GuzzleHttp\Psr7\Request object.
The new request header “Authorization” has finally been successfully added to the headers and headerNames properties of the GuzzleHttp\Psr7\Request object.

Now What?

After going so many road to resolve this, it’s time to submit this bugfix to Laravel. But it seems the story doesn’t fit if I put everything in this part, so I decided to separate it in the next chapter.

My First Pull Request to Laravel Framework — Part 3

For those of you who want to know or trying to make a pull request to Laravel, let’s have a look on that one. Thank you for reading and see you in the next part! Arigatou 🙏

Related Content