Acessando APIs com GUzzle PHP

Cada vez mais necessitamos consumir APIs de terceiros em nossos sistemas, embora o PHP tenha maneiras nativas de fazer requisições HTTP, nem sempre elas são as maneira mais ageis e simples dependendo do contexto. Então é comum utilizarmos clientes HTTP como o Guzzle, que é uma das mais populares bibliotecas para realizar requisições HTTP, ela permite realizar requisições GET, POST, PUT, DELETE e lidar com a resposta de forma fácil e com uma sintaxe agradável.

Vamos então ver alguns exemplos de como acessar uma API simples utilizando o Guzzle, para isso vamos fazer algumas requisições a uma API fake criada com uma ferramenta que estou desenvolvendo (ainda está bastante crua mas para o básico dos exemplos vai funcionar, eu acho 🙂 ). Basta baixar o projeto que roda no servidor build-in do PHP e descompactar e rodar.

cd api/
php -S localhost:8000

Uma vez com o projeto da API rodando temos os seguintes endpoints que podemos acessar:

UrlHttp MethodDescrição
/postsGETRetorna todos os posts .
/posts/1GETRetorna o post cujo o id foi passado na requisição.
/postsPOSTEspera no corpo da requisição um json com os campos “title”, “author” e “content”. Cria um novo post.
/posts/1PUTEspera no corpo da requisição um json com os campos “id”, “title”, “author” e “content”. Altera o post cujo o id foi passado na url.
/posts/1DELETEDeleta o post cujo id foi passado na url.
/headers-returnGETRetorna todos os headers passados na requisição como corpo da resposta.

Você pode ver os dados no arquivo db.json da pasta api. Ao testar verifique o arquivo para ver as alterações ou acesse a rota /posts novamente.

Agora que temos uma API para acessar, criamos um projeto PHP e instalamos o guzzle através do composer.

composer require guzzlehttp/guzzle:^7.0

Para realizar uma requisição instanciamos um objeto Client

use GuzzleHttp\Client;

$client = new Client();

Realizando uma requisição GET com Guzzle

Para realizar uma requisição utilizamos o método request, passando como argumento o método http desejado, no momento GET, e a URL que desejamos acessar.

use GuzzleHttp\Client;

$client = new Client();

$response = $client->request('GET', 'http://localhost:8000/posts');

echo "Status: " . $response->getStatusCode() . PHP_EOL;

$data = json_decode( (string) $response->getBody(), true );
echo "========= DADOS ===========\n";
print_r($data);
echo "===========================\n";

O método request irá retornar um objeto Psr\Http\Message\ResponseInterface, que é uma interface da Psr-7, nos fornecendo diversos métodos para obter informações da resposta. Na linha 7 pegamos o código de retorno HTTP através do método getStatusCode(). Na linha 9 pegamos o corpo da resposta da requisição(ou seja, o conteúdo propriamente dito) através do método getBody(). O método getBody() retorna um objeto StreamInterface que é um stream, podemos chamar o método getContents() dele para pegar o conteúdo como uma string ou simplesmente fazer um cast para string que irá chamar o __toString().

O corpo da nossa resposta é um JSON então convertemos ele para um array. Depois somente exibimos na tela seu conteúdo.

Requisição POST

Para realizar uma requisição POST é muito parecido, apenas temos que mudar o argumento do método para POST e passar como terceiro argumento o body como um dos valores do array de options da requisição. No nosso caso, um JSON.

$client = new Client();

$response = $client->request('POST', 'http://localhost:8000/posts', [
    'body' => json_encode([
        'title' => 'Titulo do post',
        'author' => 'Eu',
        'content' => 'Um texto bobo..'
    ])
]);

echo "Status: " . $response->getStatusCode() . PHP_EOL;

$data =  (string) $response->getBody();
echo "========= Body ===========\n";
echo $data;
echo "\n===========================\n";

No caso acima passamos os dados de forma crua, convertendo nós mesmos um array para JSON, mas podemos utilizar a opção json em vez de body para ele fazer a conversão automaticamente.

$response = $client->request('POST', 'http://localhost:8000/posts', [
    'json' => [
        'title' => 'Titulo do post',
        'author' => 'Eu',
        'content' => 'Um texto bobo..'
    ]
]);

Outra possibilidade é carregar o conteúdo do body de um arquivo e passar um stream para a opção body, podemos fazer isso com o método tryFopen da classe Utils.

$body = GuzzleHttp\Psr7\Utils::tryFopen('entity-post-data.json', 'r');
$response = $client->request('POST', 'http://localhost:8000/posts', [
    'body' => $body
]);

Requisição PUT

A requisição PUT é basicamente a mesma ideia da post, apenas trocamos o parâmetro do método de POST para PUT.

$client = new Client();

$response = $client->request('PUT', 'http://localhost:8000/posts/2', [
    'json' => [
        'id' => 2,
        'title' => 'Alterando titulo',
        'author' => 'Eu, mas mais bonito',
        'content' => 'Um texto ainda mais bobo..'
    ]
]);

echo "Status: " . $response->getStatusCode() . PHP_EOL;

$data =  (string) $response->getBody();
echo "========= Body ===========\n";
echo $data;
echo "\n===========================\n";

Requisição DELETE

Requisições DELETE também são bastante simples apenas mudando o método.

$client = new Client();

$response = $client->request('DELETE', 'http://localhost:8000/posts/2');

echo "Status: " . $response->getStatusCode() . PHP_EOL;

Enviando e Recebendo Headers

Para enviar headers em uma requisição passamos eles como um array associativo no array de opções da requisição com a chave headers.

No exemplo abaixo fazemos uma requisição a rota /headers-return que irá retornar todos os headers enviados na requisição como um json no body da resposta.

use GuzzleHttp\Client;

$client = new Client();
 
$response = $client->request('GET', 'http://localhost:8000/headers-return', [
    'headers' => [
        'x-my-header' => 'valor-do-header'
    ]
]);
 
echo "Status: " . $response->getStatusCode() . PHP_EOL;
 
$data = (string) $response->getBody();
echo "========= Response com os Headers Request ===========\n";
echo $data . PHP_EOL;
echo "=====================================\n";
 
$headersResponse = $response->getHeaders(); // pegando os headers da resposta
echo "========= Headers Response ===========\n";
print_r($headersResponse);
echo "=====================================\n";

No bloco de código acima pegamos os headers da resposta através do método getHeaders do objeto $response, lembrando que o response é um objeto ResponseInterface da Psr7 fornecendo todos os métodos do padrão.

Autenticação HTTP Basic

O Guzzle permite enviar as credenciais da autenticação http basic de forma muito fácil, bastando passar um array com o usuário e senha para o array de opções com a chave auth. Ele irá automáticamente criar o token e enviar no header.

$client = new Client();

try{
    $response = $client->request('GET', 'http://localhost:8000/protegido', [
        'auth' => ['rodrigo','123456']
    ]);

    echo "Status: " . $response->getStatusCode() . PHP_EOL;
}catch(BadResponseException $e){
    echo $e->getResponse()->getStatusCode() . PHP_EOL;
    echo (string) $e->getResponse()->getBody();
}

Caso passarmos um usuário ou senha errados e ele retornar uma resposta 401, isso irá lançar uma exceção que pode ser capturada com o objeto response através do método getResponse da exceção. Altere a senha e teste.

Bom era isso uma pequena introdução ao Guzzle, esse cliente Http bastante simples e poderoso, para mais detalhes veja a documentação. T++