Back-End

2 nov, 2018

Padrão novo no PHP – PSR-18 (HTTP Client)

Publicidade

Fala pessoal, tudo bom? Hoje vamos sair um pouco das bibliotecas e falar um pouco sobre uma nova PSR que foi aprovada essa semana.

Para quem não sabe, as PSRs (PHP Standards Recommendations) são recomendações de “padrões” para algumas características em PHP.  Por exemplo, temos padrões de autoload (PSR-4), padrões de escrita de código (PSR-1 e PSR-2), padrões de logging (PSR-3), caching (PSR-6), entre outras. A idéia é que tenhamos uma pequena padronização entre os frameworks e demais projetos. Essas PSRs são propostas pelo PHP-FIG.

O PHP-FIG (The PHP Framework Interop Group) é um grupo formado de líderes de grandes projetos PHP. E eles propõem alguns modelos de padrões para que fique mais fácil a integração entre os diversos projetos PHP. Esses padrões nem sempre são seguidos e nem obrigatórios. Mas, quando utilizados facilitam demais a vida de quem programa em PHP.

A PSR-18 trata de interfaces para HTTP Clients. Um HTTP Client é uma biblioteca que tem como objetivo enviar mensagens de solicitação HTTP e retornar uma mensagem de resposta HTTP.

Vamos ver como ficou o texto da PSR:

Original em: https://www.php-fig.org/psr/psr-18/

Objetivo

O objetivo deste PSR é permitir que os desenvolvedores criem bibliotecas desacopladas das implementações do Client HTTP. Isso tornará as bibliotecas mais reutilizáveis, pois reduz o número de dependências e reduz a probabilidade de conflitos de versões.

Um segundo objetivo é que os Clients HTTP possam ser substituídos de acordo com o princípio da substituição de Liskov. Isso significa que todos os Clients DEVEM se comportar da mesma maneira ao enviar uma solicitação.

Definições

Client – Um Client é uma biblioteca que implementa essa especificação com o objetivo de enviar mensagens de solicitação HTTP compatíveis com o PSR-7 e retornar uma mensagem de resposta HTTP compatível com o PSR-7 para uma Calling Library.

Calling Library – Uma calling library é qualquer código que faz uso de um Client. Ele não implementa as interfaces desta especificação, mas consome um objeto que as implementa (um Client).

Client

Um Client é um objeto que implementa ClientInterface.

Um Client pode:

Optar por enviar uma solicitação HTTP alterada daquela que foi fornecida. Por exemplo, poderia compactar um corpo de mensagem de saída.

Optar por alterar uma resposta HTTP recebida antes de retorná-la a Calling Library. Por exemplo, ele poderia descompactar um corpo de mensagem de entrada.

Se um Client optar por alterar a solicitação HTTP ou a resposta HTTP, ele DEVE garantir que o objeto permaneça internamente consistente. Por exemplo, se um Client optar por descompactar o corpo da mensagem, ele também deverá remover o cabeçalho Content-Encoding e ajustar o cabeçalho Content-Length.

Note que, como resultado, como os objetos PSR-7 são imutáveis, a Calling Library NÃO DEVE assumir que o objeto passado para ClientInterface::sendRequest() será o mesmo objeto PHP que é realmente enviado. Por exemplo, o objeto Request que é retornado por uma exceção PODE ser um objeto diferente daquele passado para sendRequest(), portanto, a comparação por referência (===) não é possível.

Um Client deve:

Remontar uma resposta HTTP 1xx de várias etapas para que o que é retornado para a Calling Library seja uma resposta HTTP válida do código de status 200 ou superior.

Tratamento de erros

Um Client não deve tratar uma solicitação HTTP bem formada ou uma resposta HTTP como uma condição de erro. Por exemplo, os códigos de status de resposta nas faixas 400 e 500 NÃO PODEM causar uma exceção e DEVEM ser devolvidos a Calling Library normalmente.

Um Client deve lançar uma instância de Psr\Http\Client\ClientxceptionInterface se, e somente se, ele não puder enviar a solicitação HTTP ou se a resposta HTTP não puder ser analisada em um objeto de resposta PSR-7.

Se uma solicitação não pode ser enviada porque a mensagem de solicitação não é uma solicitação HTTP bem formada ou está faltando alguma informação crítica (como um host ou método), o Client deve lançar uma instância de Psr\Http\Client\RequestExceptionInterface.

Se a solicitação não puder ser enviada devido a uma falha de rede de qualquer tipo, incluindo um tempo limite, o Client DEVE lançar uma instância de Psr\Http\Client\NetworkExceptionInterface.

Os Clients podem lançar exceções mais específicas do que as definidas aqui (um TimeOutException ou HostNotFoundException, por exemplo), desde que implementem a interface apropriada definida acima.

Interfaces

Client Interface

namespace Psr\Http\Client;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface ClientInterface
{
    /**
     * Sends a PSR-7 request and returns a PSR-7 response.
     *
     * @param RequestInterface $request
     *
     * @return ResponseInterface
     *
     * @throws \Psr\Http\Client\ClientExceptionInterface If an error happens while processing the request.
     */
    public function sendRequest(RequestInterface $request): ResponseInterface;
}

ClientExceptionInterface

namespace Psr\Http\Client;

/**
 * Toda exceção relacionada ao HTTP Client DEVE implementar essa interface.
 */
interface ClientExceptionInterface extends \Throwable
{
}

RequestExceptionInterface

namespace Psr\Http\Client;

use Psr\Http\Message\RequestInterface;

/**
 * Exceção para quando uma solicitação falhou.
 *
 * Exemplos:
 *      - A solicitação é inválida (por exemplo, o método está ausente)
 *      - Erros de solicitação de tempo de execução (por exemplo, o fluxo do corpo não é pesquisavel)
 */
interface RequestExceptionInterface extends ClientExceptionInterface
{
    /**
     * Returns the request.
     *
     * The request object MAY be a different object from the one passed to ClientInterface::sendRequest()
     *
     * @return RequestInterface
     */
    public function getRequest(): RequestInterface;
}

NetworkExceptionInterface

namespace Psr\Http\Client;

use Psr\Http\Message\RequestInterface;

/**
 * Lançada quando a solicitação não pode ser concluída devido a problemas de rede.
 *
 * Não há objeto de resposta, pois essa exceção é lançada quando nenhuma resposta é recebida.
 *
 * Exemplo: o nome do host de destino não pode ser resolvido ou a conexão falhou.
 */
interface NetworkExceptionInterface extends ClientExceptionInterface
{
    /**
     * Retorna a requisição
     *
     * O objeto request pode ser um objeto diferente daquele passado para ClientInterface::sendRequest()
     *
     * @return RequestInterface
     */
    public function getRequest(): RequestInterface;
}

Em breve veremos essas implementações na maioria dos Clients HTTP e será muito mais fácil as integrações.

Um grande abraço, até a próxima.