Skip to content

Commit 188999c

Browse files
committed
feat: make requests with a base url and a client builder
1 parent 7378d85 commit 188999c

File tree

6 files changed

+174
-4
lines changed

6 files changed

+174
-4
lines changed

Diff for: .ddev/config.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ omit_containers: [db]
1313
use_dns_when_possible: true
1414
composer_version: "2"
1515
web_environment: []
16+
disable_upload_dirs_warning: true
1617

1718
# Key features of DDEV's config.yaml:
1819

Diff for: composer.json

+18-4
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,38 @@
1212
}
1313
],
1414
"require": {
15-
"php": ">=8.1"
15+
"php": ">=8.1",
16+
"php-http/client-common": "^2.7",
17+
"php-http/discovery": "^1.19",
18+
"programmatordev/yet-another-php-validator": "^0.6.0",
19+
"psr/http-client": "^1.0",
20+
"psr/http-factory": "^1.0"
1621
},
1722
"require-dev": {
23+
"nyholm/psr7": "^1.8",
1824
"phpunit/phpunit": "^10.0",
25+
"symfony/http-client": "^6.4",
1926
"symfony/var-dumper": "^6.4"
2027
},
28+
"provide": {
29+
"psr/http-client-implementation": "1.0",
30+
"psr/http-factory-implementation": "1.0"
31+
},
2132
"autoload": {
2233
"psr-4": {
23-
"ProgrammatorDev\\PhpApiSdk\\": "src/"
34+
"ProgrammatorDev\\Api\\": "src/"
2435
}
2536
},
2637
"autoload-dev": {
2738
"psr-4": {
28-
"ProgrammatorDev\\PhpApiSdk\\Test\\": "tests/"
39+
"ProgrammatorDev\\Api\\Test\\": "tests/"
2940
}
3041
},
3142
"config": {
3243
"optimize-autoloader": true,
33-
"sort-packages": true
44+
"sort-packages": true,
45+
"allow-plugins": {
46+
"php-http/discovery": true
47+
}
3448
}
3549
}

Diff for: src/Api.php

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Api;
4+
5+
use Http\Client\Exception;
6+
use ProgrammatorDev\Api\Client\ClientBuilder;
7+
use ProgrammatorDev\Api\Exception\MissingConfigException;
8+
use ProgrammatorDev\Api\Helper\StringHelperTrait;
9+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\ValidationException;
10+
use ProgrammatorDev\YetAnotherPhpValidator\Validator;
11+
use Psr\Http\Message\ResponseInterface;
12+
use Psr\Http\Message\StreamInterface;
13+
14+
class Api
15+
{
16+
use StringHelperTrait;
17+
18+
private ?string $baseUrl = null;
19+
20+
private ?ClientBuilder $clientBuilder = null;
21+
22+
public function __construct()
23+
{
24+
$this->clientBuilder ??= new ClientBuilder();
25+
}
26+
27+
/**
28+
* @throws MissingConfigException
29+
* @throws Exception
30+
*/
31+
public function request(
32+
string $method,
33+
string $path,
34+
array $query = [],
35+
array $headers = [],
36+
string|StreamInterface $body = null
37+
): ResponseInterface
38+
{
39+
if (!$this->getBaseUrl()) {
40+
throw new MissingConfigException('A base URL must be set');
41+
}
42+
43+
return $this->clientBuilder->getClient()->send(
44+
$method,
45+
$this->createUri($path, $query),
46+
$headers,
47+
$body
48+
);
49+
}
50+
51+
protected function getBaseUrl(): ?string
52+
{
53+
return $this->baseUrl;
54+
}
55+
56+
/**
57+
* @throws ValidationException
58+
*/
59+
protected function setBaseUrl(string $baseUrl): self
60+
{
61+
Validator::url()->assert($baseUrl);
62+
63+
$this->baseUrl = $baseUrl;
64+
65+
return $this;
66+
}
67+
68+
protected function getClientBuilder(): ?ClientBuilder
69+
{
70+
return $this->clientBuilder;
71+
}
72+
73+
protected function setClientBuilder(ClientBuilder $clientBuilder): self
74+
{
75+
$this->clientBuilder = $clientBuilder;
76+
77+
return $this;
78+
}
79+
80+
private function createUri(string $path, array $query = []): string
81+
{
82+
$uri = $this->reduceDoubleSlashes($this->getBaseUrl() . $path);
83+
84+
if (!empty($query)) {
85+
$uri = \sprintf('%s?%s', $uri, \http_build_query($query));
86+
}
87+
88+
return $uri;
89+
}
90+
}

Diff for: src/Client/ClientBuilder.php

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Api\Client;
4+
5+
use Http\Client\Common\HttpMethodsClient;
6+
use Http\Client\Common\Plugin;
7+
use Http\Client\Common\PluginClientFactory;
8+
use Http\Discovery\Psr17FactoryDiscovery;
9+
use Http\Discovery\Psr18ClientDiscovery;
10+
use Psr\Http\Client\ClientInterface;
11+
use Psr\Http\Message\RequestFactoryInterface;
12+
use Psr\Http\Message\StreamFactoryInterface;
13+
14+
class ClientBuilder
15+
{
16+
/** @var Plugin[] */
17+
private array $plugins = [];
18+
19+
public function __construct(
20+
private ?ClientInterface $client = null,
21+
private ?RequestFactoryInterface $requestFactory = null,
22+
private ?StreamFactoryInterface $streamFactory = null
23+
)
24+
{
25+
$this->client ??= Psr18ClientDiscovery::find();
26+
$this->requestFactory ??= Psr17FactoryDiscovery::findRequestFactory();
27+
$this->streamFactory ??= Psr17FactoryDiscovery::findStreamFactory();
28+
}
29+
30+
public function getClient(): HttpMethodsClient
31+
{
32+
$this->addPlugin(new Plugin\ContentTypePlugin());
33+
$this->addPlugin(new Plugin\ContentLengthPlugin());
34+
35+
$pluginClientFactory = new PluginClientFactory();
36+
$client = $pluginClientFactory->createClient($this->client, $this->plugins);
37+
38+
return new HttpMethodsClient(
39+
$client,
40+
$this->requestFactory,
41+
$this->streamFactory
42+
);
43+
}
44+
45+
public function addPlugin(Plugin $plugin): void
46+
{
47+
$this->plugins[] = $plugin;
48+
}
49+
}

Diff for: src/Exception/MissingConfigException.php

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Api\Exception;
4+
5+
class MissingConfigException extends \LogicException {}

Diff for: src/Helper/StringHelperTrait.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\Api\Helper;
4+
5+
trait StringHelperTrait
6+
{
7+
private function reduceDoubleSlashes(string $string): string
8+
{
9+
return \preg_replace('#(^|[^:])//+#', '\\1/', $string);
10+
}
11+
}

0 commit comments

Comments
 (0)