mollie-api-php icon indicating copy to clipboard operation
mollie-api-php copied to clipboard

Allow PSR-18 Http Clients

Open KDederichs opened this issue 1 year ago • 5 comments

Specifications

  • API Version: 2.63.0

Describe the issue

Hi,

I was wondering if you guys could add PSR18 (https://github.com/php-fig/http-client) as supported option for Http Clients.

The reason I'm asking is I'd like to use something like https://docs.php-http.org/en/latest/clients/mock-client.html in integration tests to mock mollie responses.

Sadly it currently only seems to support Guzzle's ClientInterface and your own one.

KDederichs avatar Nov 09 '23 11:11 KDederichs

Hi @KDederichs,

thanks for your suggestion. I will discuss this internally.

Nevertheless, this would be a breaking change and therefore won’t be included in any release before v3, which is scheduled for early next year.

Naoray avatar Nov 10 '23 11:11 Naoray

How about adding a Mollie\Api\HttpAdapter\PSR18MollieHttpAdapter here that implements the Mollie\Api\HttpAdapter\ MollieHttpAdapterInterface, which in turn accepts a PSR18 enabled client on the constructor? I think that way it's possible to introduce PSR18 support without a breaking change.

@KDederichs would you need PSR17 support as well (RequestFactoryInterface, StreamFactoryInterface)?

sandervanhooft avatar Jun 07 '24 13:06 sandervanhooft

For example (not tested):

<?php

namespace Mollie\Api\HttpAdapter;

use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Mollie\Api\Exceptions\ApiException;

class PSR18MollieHttpAdapter implements MollieHttpAdapterInterface
{
    /**
     * @var ClientInterface
     */
    private $httpClient;

    /**
     * @var RequestFactoryInterface
     */
    private $requestFactory;

    /**
     * @var StreamFactoryInterface
     */
    private $streamFactory;

    /**
     * PSR18MollieHttpAdapter constructor.
     *
     * @param ClientInterface $httpClient
     * @param RequestFactoryInterface $requestFactory
     * @param StreamFactoryInterface $streamFactory
     */
    public function __construct(ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory)
    {
        $this->httpClient = $httpClient;
        $this->requestFactory = $requestFactory;
        $this->streamFactory = $streamFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function send($httpMethod, $url, $headers, $httpBody)
    {
        try {
            $request = $this->createRequest($httpMethod, $url, $headers, $httpBody);
            $response = $this->httpClient->sendRequest($request);

            $body = (string) $response->getBody();
            return json_decode($body);
        } catch (\Exception $e) {
            throw new ApiException("Error while sending request to Mollie API: " . $e->getMessage(), 0, $e);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function versionString()
    {
        return 'PSR18MollieHttpAdapter';
    }

    /**
     * Create a PSR-7 request.
     *
     * @param string $httpMethod
     * @param string $url
     * @param string|array $headers
     * @param string $httpBody
     * @return RequestInterface
     */
    private function createRequest($httpMethod, $url, $headers, $httpBody)
    {
        $request = $this->requestFactory->createRequest($httpMethod, $url);
        
        if (is_array($headers)) {
            foreach ($headers as $name => $value) {
                $request = $request->withHeader($name, $value);
            }
        } else {
            // Assuming headers is a string in the form of 'Header-Name: Header-Value'
            $headerLines = explode("\r\n", $headers);
            foreach ($headerLines as $line) {
                list($name, $value) = explode(': ', $line, 2);
                $request = $request->withHeader($name, $value);
            }
        }
        
        $stream = $this->streamFactory->createStream($httpBody);
        $request = $request->withBody($stream);
        
        return $request;
    }
}

sandervanhooft avatar Jun 07 '24 13:06 sandervanhooft

That looks like it would work yeah.

KDederichs avatar Jun 07 '24 16:06 KDederichs

@Naoray what do you think?

sandervanhooft avatar Jun 12 '24 12:06 sandervanhooft