Skip to content

Commit d44459d

Browse files
authored
Merge pull request #13 from programmatordev/PAS-11-improve-uri-build
Improve URL build
2 parents 842480a + 3c83bff commit d44459d

File tree

5 files changed

+45
-10
lines changed

5 files changed

+45
-10
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class YourApi extends Api
6969
- [HTTP client (PSR-18) and HTTP factories (PSR-17)](#http-client-psr-18-and-http-factories-psr-17)
7070
- [Cache (PSR-6)](#cache-psr-6)
7171
- [Logger (PSR-3)](#logger-psr-3)
72-
- [Configure options](#configure-options)
7372

7473
### Base URL
7574

@@ -142,6 +141,9 @@ By default, this method will return a `string` as it will be the response of the
142141
If you want to change how the response is handled in all requests (for example, decode a JSON string into an array),
143142
check the [`addResponseContentsListener`](#addresponsecontentslistener) method in the [Event Listeners](#event-listeners) section.
144143

144+
> [!NOTE]
145+
> If the `path` set is a full URL, it will be used as the request URL even if a `baseUrl` is set.
146+
145147
#### `buildPath`
146148

147149
The purpose of this method is to have an easy way to build a properly formatted path depending on the inputs or parameters you might have.

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
],
1414
"require": {
1515
"php": ">=8.1",
16+
"nyholm/append-query-string": "^1.0",
1617
"php-http/cache-plugin": "^2.0",
1718
"php-http/client-common": "^2.7",
1819
"php-http/discovery": "^1.20",

src/Api.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ public function request(
6666
$headers = array_merge($this->headerDefaults, $headers);
6767
}
6868

69-
$uri = $this->buildUri($path, $query);
70-
$request = $this->createRequest($method, $uri, $headers, $body);
69+
$url = $this->buildUrl($path, $query);
70+
$request = $this->createRequest($method, $url, $headers, $body);
7171

7272
// pre request listener
7373
$request = $this->eventDispatcher->dispatch(new PreRequestEvent($request))->getRequest();
@@ -276,25 +276,26 @@ public function buildPath(string $path, array $parameters): string
276276
return $path;
277277
}
278278

279-
private function buildUri(string $path, array $query = []): string
279+
private function buildUrl(string $path, array $query = []): string
280280
{
281-
$uri = StringHelper::reduceDuplicateSlashes($this->baseUrl . $path);
281+
$appendQuery = http_build_query($query);
282282

283-
if (!empty($query)) {
284-
$uri = sprintf('%s?%s', $uri, http_build_query($query));
283+
if (StringHelper::isUrl($path)) {
284+
return append_query_string($path, $appendQuery, APPEND_QUERY_STRING_REPLACE_DUPLICATE);
285285
}
286286

287-
return $uri;
287+
$url = StringHelper::reduceDuplicateSlashes($this->baseUrl . $path);
288+
return append_query_string($url, $appendQuery, APPEND_QUERY_STRING_REPLACE_DUPLICATE);
288289
}
289290

290291
private function createRequest(
291292
string $method,
292-
string $uri,
293+
string $url,
293294
array $headers = [],
294295
string|StreamInterface $body = null
295296
): RequestInterface
296297
{
297-
$request = $this->clientBuilder->getRequestFactory()->createRequest($method, $uri);
298+
$request = $this->clientBuilder->getRequestFactory()->createRequest($method, $url);
298299

299300
foreach ($headers as $key => $value) {
300301
$request = $request->withHeader($key, $value);

src/Helper/StringHelper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@ public static function reduceDuplicateSlashes(string $string): string
88
{
99
return preg_replace('#(^|[^:])//+#', '\\1/', $string);
1010
}
11+
12+
public static function isUrl(string $string): bool
13+
{
14+
return filter_var($string, FILTER_VALIDATE_URL) !== false;
15+
}
1116
}

tests/Integration/ApiTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
use Http\Message\Authentication;
66
use Http\Mock\Client;
77
use Nyholm\Psr7\Response;
8+
use PHPUnit\Framework\Attributes\DataProvider;
89
use ProgrammatorDev\Api\Api;
910
use ProgrammatorDev\Api\Builder\CacheBuilder;
1011
use ProgrammatorDev\Api\Builder\ClientBuilder;
1112
use ProgrammatorDev\Api\Builder\LoggerBuilder;
13+
use ProgrammatorDev\Api\Event\PreRequestEvent;
1214
use ProgrammatorDev\Api\Event\ResponseContentsEvent;
1315
use ProgrammatorDev\Api\Test\AbstractTestCase;
1416
use ProgrammatorDev\Api\Test\MockResponse;
@@ -192,6 +194,30 @@ public function testResponseContentsListener()
192194
$this->assertIsArray($response);
193195
}
194196

197+
#[DataProvider('provideBuildUrlData')]
198+
public function testBuildUrl(?string $baseUrl, string $path, array $query, string $expectedUrl)
199+
{
200+
$this->api->addPreRequestListener(function(PreRequestEvent $event) use ($expectedUrl) {
201+
$url = (string) $event->getRequest()->getUri();
202+
203+
$this->assertSame($expectedUrl, $url);
204+
});
205+
206+
$this->api->setBaseUrl($baseUrl);
207+
$this->api->request(method: 'GET', path: $path, query: $query);
208+
}
209+
210+
public static function provideBuildUrlData(): \Generator
211+
{
212+
yield 'no base url' => [null, '/path', [], '/path'];
213+
yield 'base url' => [self::BASE_URL, '/path', [], 'https://base.com/url/path'];
214+
yield 'path full url' => [self::BASE_URL, 'https://fullurl.com/path', [], 'https://fullurl.com/path'];
215+
yield 'duplicated slashes' => [self::BASE_URL, '////path', [], 'https://base.com/url/path'];
216+
yield 'query' => [self::BASE_URL, '/path', ['foo' => 'bar'], 'https://base.com/url/path?foo=bar'];
217+
yield 'path query' => [self::BASE_URL, '/path?test=true', ['foo' => 'bar'], 'https://base.com/url/path?test=true&foo=bar'];
218+
yield 'query replace' => [self::BASE_URL, '/path?test=true', ['test' => 'false'], 'https://base.com/url/path?test=false'];
219+
}
220+
195221
public function testBuildPath()
196222
{
197223
$path = $this->api->buildPath('/path/{parameter1}/multiple/{parameter2}', [

0 commit comments

Comments
 (0)