Photo by Sean Lim on Unsplash

There are tons of articles online explaining how to use GuzzleHTTP to consume HTTP services from any PHP project and of course from a Laravel project.

(Follow me on Twitter for tips and ideas on Laravel and Web Development)

Now, the major part of those articles show you how to create an instance of the Client class of Guzzle, send the request and obtain the response, something like this:

use GuzzleHttp\Client; $client = new Client([

'base_uri' => $this->baseUri,

]); $response = $client->request($method, $requestUrl, [

'query' => $queryParams,

'form_params' => $formParams,

'headers' => $headers,

]); $response = $response->getBody()->getContents();

The problem…

Unfortunately, several of those articles just are focused on how to directly use GuzzleHTTP from any Laravel component (usually a Controller) and then return the response, but… What happens if you need to consume several services OR even when consumes the same service from different parts of your Laravel projects? Let’s say you need to consume a determined HTTP service from the action foo() of your BarController and then from the bar() of your FooController, and maybe from any specific model, service, etc.

So, after that, you may be finishing repeating calls to the Client class of GuzzleHTTP across your entire project, which may sound fine as GuzzleHTTP provides a good abstraction level for HTTP requests, BUT there is an even better way to adapt your calls to Client class and centralize that in your projects.

Basically, after all, what you need is to provide the capability to send HTTP requests to your project, to any URL with any HTTP method (POST, PUT, PATCH, DELETE, etc.), and, of course, with whatever body contents and even query parameters.

So, after developing several HTTP clients for clients, my side projects, and my courses, I found that the traits in PHP are a very flexible solution to add the capability to consume any external service. In that way, any component of your project that uses this trait will be capable to send requests.

Finally, after this “introduction”, let me show you a proposal for a trait that should probably consume any kind of HTTP service, using Guzzle of course:

namespace App\Traits; use GuzzleHttp\Client;

{

/**

* Send a request to any service

*

*/

public function makeRequest($method, $requestUrl, $queryParams = [], $formParams = [], $headers = [], $hasFile = false)

{

$client = new Client([

'base_uri' => $this->baseUri,

]); trait ConsumesExternalServices/*** Send a request to any service @return string*/public function makeRequest($method, $requestUrl, $queryParams = [], $formParams = [], $headers = [], $hasFile = false)$client = new Client(['base_uri' => $this->baseUri,]); $bodyType = 'form_params'; if ($hasFile) {

$bodyType = 'multipart'; $multipart = []; foreach ($formParams as $name => $contents) {

$multipart[] = [

'name' => $name,

'contents' => $contents

];

}

} $response = $client->request($method, $requestUrl, [

'query' => $queryParams,

$bodyType => $hasFile ? $multipart : $formParams,

'headers' => $headers,

]); $response = $response->getBody()->getContents(); return $response;

}

}

Basically, you are generalizing the calls to the request() method of the Client class from Guzzle, allowing any HTTP method, any URL, and optionally, any query params, form params headers AND very important sending files.

Noticed that? YES nobody told you that sending files with GuzzleHTTP is slightly different than sending regular requests. You need to specify a multipart, instead of a form_params, and additionally, you need to format differently every field of the body, as all of them need a “name” and “content” values (that is why there is a foreach() there).

Now, once you have this trait, you can use it and call that from any component, let’s see a short example:

namespace App\Services; use App\Traits\ConsumesExternalServices; class MyExternalService

{

$baseUri = 'someUri';

//Or better take that from the config() in the __construct() use ConsumesExternalServices; public function getUsers()

{

$this->makeRequest('GET', '/users');

} public function createUser($data)

{

$this->makeRequest('POST', '/users', [], $data);

}

...

}

So… did we finish already? Not so fast, there are some other things you can do to improve the scalability of your projects using this trait and be able to consume any service you need. For example, you may want to customize the way every service you consume resolves the authorization flow (sending a query param with a token? or sending an Authorization header with an access token? or something else?). Additionally, the way as the response is parsed after obtaining it (is it JSON? XML? plaintext? HTML?). I can help you to resolve that correctly, with this course.

By the way, I created a small package to re-utilize this trait (and some other components) across all my projects, so you probably can do the same.

Finally, you may want to separate every service you consume in a Service class (or a set of services) where you can specify how to do a specific action (get users, get posts, publish something, etc.)

Now, there are several other things you need to resolve. So, let me help you with that. I already show you a good way to go, but I can surely show you much more. Let me teach you how to integrate Laravel and Guzzle to consume any HTTP service. Let me show you how to create your HTTP Client with Laravel.

We are done here. I hope you can find this useful for your projects and your career. If you are interested in any of my courses, here it is my portfolio, or you can take directly the HTTP Clients course.

Best wishes :)