Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest, windows-latest]
php: [8.3, 8.2, 8.1]
php: [8.4, 8.3, 8.2, 8.1]
stability: [prefer-lowest, prefer-stable]

name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
Expand Down Expand Up @@ -40,4 +40,4 @@ jobs:
uses: codecov/codecov-action@v5
with:
file: ./coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@
"scripts": {
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
"format": "vendor/bin/pint",
"analyse": "vendor/bin/phpstan analyse",
"check": [
"@analyse",
"@test"
]
},
"config": {
"sort-packages": true,
Expand Down
61 changes: 37 additions & 24 deletions examples/advanced-retry.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Advanced Retry Logic Example
*
Expand Down Expand Up @@ -61,13 +63,22 @@
echo "3. Custom Retry Conditions\n";
echo str_repeat('-', 50)."\n";

$retryableStatusCodes = [408, 429, 500, 502, 503, 504];

$transport3 = TransportBuilder::make()
->withBaseUri('https://jsonplaceholder.typicode.com')
->withRetries(
maxRetries: 5,
strategy: new ExponentialBackoffStrategy,
strategy: new ExponentialBackoffStrategy(),
condition: RetryCondition::default()
->onStatusCodes([408, 429, 500, 502, 503, 504]) // Retry on specific status codes
->when(function (\Throwable $exception, \Farzai\Transport\Retry\RetryContext $context) use ($retryableStatusCodes): bool {
// Retry on specific status codes from HTTP exceptions
if ($exception instanceof \Farzai\Transport\Exceptions\HttpException && $exception->hasResponse()) {
return in_array($exception->getResponse()->getStatusCode(), $retryableStatusCodes, true);
}

return false;
})
)
->build();

Expand All @@ -83,34 +94,36 @@
echo "4. Retry with Custom Condition Callback\n";
echo str_repeat('-', 50)."\n";

$transport4 = TransportBuilder::make()
->withBaseUri('https://jsonplaceholder.typicode.com')
->withRetries(
maxRetries: 3,
strategy: new ExponentialBackoffStrategy,
condition: RetryCondition::fromCallback(
function (\Throwable $exception, \Farzai\Transport\Retry\RetryContext $context): bool {
echo " Retry attempt {$context->attempt}/{$context->maxAttempts}\n";
echo " Exception: {$exception->getMessage()}\n";
$customCondition = (new RetryCondition())->when(
function (\Throwable $exception, \Farzai\Transport\Retry\RetryContext $context): bool {
echo " Retry attempt {$context->attempt}/{$context->maxAttempts}\n";
echo " Exception: {$exception->getMessage()}\n";

// Retry only on network errors or 5xx responses
if ($exception instanceof \Farzai\Transport\Exceptions\ServerException) {
echo " Decision: RETRY (Server error)\n\n";
// Retry only on network errors or 5xx responses
if ($exception instanceof \Farzai\Transport\Exceptions\ServerException) {
echo " Decision: RETRY (Server error)\n\n";

return true;
}
return true;
}

if ($exception instanceof \Farzai\Transport\Exceptions\NetworkException) {
echo " Decision: RETRY (Network error)\n\n";
if ($exception instanceof \Farzai\Transport\Exceptions\NetworkException) {
echo " Decision: RETRY (Network error)\n\n";

return true;
}
return true;
}

echo " Decision: DO NOT RETRY\n\n";
echo " Decision: DO NOT RETRY\n\n";

return false;
}
)
return false;
}
);

$transport4 = TransportBuilder::make()
->withBaseUri('https://jsonplaceholder.typicode.com')
->withRetries(
maxRetries: 3,
strategy: new ExponentialBackoffStrategy(),
condition: $customCondition
)
->build();

Expand Down
2 changes: 2 additions & 0 deletions examples/basic-usage.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Basic Usage Example
*
Expand Down
18 changes: 10 additions & 8 deletions examples/cookie-session.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Cookie Session Example
*
Expand Down Expand Up @@ -50,7 +52,7 @@
echo str_repeat('-', 50)."\n";

try {
$cookieJar = new CookieJar;
$cookieJar = new CookieJar();

$transport = TransportBuilder::make()
->withBaseUri('https://httpbin.org')
Expand Down Expand Up @@ -84,7 +86,7 @@
echo str_repeat('-', 50)."\n";

try {
$cookieJar = new CookieJar;
$cookieJar = new CookieJar();

// Manually create and add cookies
$sessionCookie = new Cookie(
Expand Down Expand Up @@ -129,7 +131,7 @@
echo str_repeat('-', 50)."\n";

try {
$cookieJar = new CookieJar;
$cookieJar = new CookieJar();

// Add various cookies
$cookieJar->setCookie(new Cookie('cookie1', 'value1', null, 'example.com', '/'));
Expand Down Expand Up @@ -167,7 +169,7 @@

try {
// Create jar and add cookies
$jar1 = new CookieJar;
$jar1 = new CookieJar();
$jar1->setCookie(new Cookie('persistent', 'data', time() + 86400, 'example.com'));
$jar1->setCookie(new Cookie('preferences', 'dark_mode=true', time() + 2592000, 'example.com'));

Expand All @@ -181,7 +183,7 @@
echo "Cookies saved to: {$cookieFile}\n";

// Later... Import cookies
$jar2 = new CookieJar;
$jar2 = new CookieJar();
$imported = json_decode(file_get_contents($cookieFile), true);
$jar2->fromArray($imported);

Expand All @@ -199,7 +201,7 @@
echo str_repeat('-', 50)."\n";

try {
$cookieJar = new CookieJar;
$cookieJar = new CookieJar();

// Add mix of cookies
$cookieJar->setCookie(new Cookie('keep', 'value', time() + 3600));
Expand All @@ -224,7 +226,7 @@
echo str_repeat('-', 50)."\n";

try {
$cookieJar = new CookieJar;
$cookieJar = new CookieJar();

// Create transport for scraping
$scraper = TransportBuilder::make()
Expand Down Expand Up @@ -262,7 +264,7 @@

try {
// Without session persistence (default)
$regularJar = new CookieJar;
$regularJar = new CookieJar();
$regularJar->setCookie(new Cookie('session', 'value')); // Session cookie
$regularJar->setCookie(new Cookie('persistent', 'value', time() + 3600)); // Persistent

Expand Down
5 changes: 3 additions & 2 deletions examples/custom-client.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Custom HTTP Client Example
*
Expand Down Expand Up @@ -116,8 +118,7 @@

try {
// Create a simple logger
$logger = new class extends \Psr\Log\AbstractLogger
{
$logger = new class () extends \Psr\Log\AbstractLogger {
public function log($level, $message, array $context = []): void
{
$contextStr = ! empty($context) ? ' '.json_encode($context) : '';
Expand Down
4 changes: 3 additions & 1 deletion examples/file-upload.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* File Upload Example
*
Expand Down Expand Up @@ -134,7 +136,7 @@

try {
// Create builder
$builder = new MultipartStreamBuilder;
$builder = new MultipartStreamBuilder();

// Add various fields
$builder->addField('user_id', '12345')
Expand Down
16 changes: 11 additions & 5 deletions examples/middleware-example.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/**
* Custom Middleware Example
*
Expand All @@ -25,7 +27,8 @@ class CustomHeaderMiddleware implements MiddlewareInterface
public function __construct(
private readonly string $headerName,
private readonly string $headerValue
) {}
) {
}

public function handle(RequestInterface $request, callable $next): ResponseInterface
{
Expand Down Expand Up @@ -87,7 +90,7 @@ public function handle(RequestInterface $request, callable $next): ResponseInter
$transport2 = TransportBuilder::make()
->withBaseUri('https://jsonplaceholder.typicode.com')
->withoutDefaultMiddlewares() // Disable default logging
->withMiddleware(new DetailedLoggingMiddleware)
->withMiddleware(new DetailedLoggingMiddleware())
->build();

try {
Expand All @@ -105,7 +108,8 @@ class ApiKeyAuthMiddleware implements MiddlewareInterface
public function __construct(
private readonly string $apiKey,
private readonly string $headerName = 'X-API-Key'
) {}
) {
}

public function handle(RequestInterface $request, callable $next): ResponseInterface
{
Expand Down Expand Up @@ -138,7 +142,8 @@ class SimpleCacheMiddleware implements MiddlewareInterface

public function __construct(
private readonly int $ttlSeconds = 60
) {}
) {
}

public function handle(RequestInterface $request, callable $next): ResponseInterface
{
Expand Down Expand Up @@ -204,7 +209,8 @@ class RateLimitMiddleware implements MiddlewareInterface
public function __construct(
private readonly int $maxRequests = 10,
private readonly int $perSeconds = 60
) {}
) {
}

public function handle(RequestInterface $request, callable $next): ResponseInterface
{
Expand Down
11 changes: 11 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
parameters:
level: 8
paths:
- src
excludePaths:
- vendor
checkGenericClassInNonGenericObjectType: true
reportUnmatchedIgnoredErrors: false
ignoreErrors:
-
identifier: missingType.iterableValue
21 changes: 21 additions & 0 deletions pint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"preset": "psr12",
"rules": {
"array_syntax": {
"syntax": "short"
},
"binary_operator_spaces": {
"default": "single_space"
},
"blank_line_after_opening_tag": true,
"declare_strict_types": true,
"no_unused_imports": true,
"ordered_imports": {
"sort_algorithm": "alpha"
},
"single_quote": true,
"trailing_comma_in_multiline": {
"elements": ["arrays"]
}
}
}
2 changes: 1 addition & 1 deletion src/Contracts/ResponseInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function toArray(): array;
*
* @throws \Psr\Http\Client\ClientExceptionInterface
*/
public function throw(?callable $callback = null);
public function throw(?callable $callback = null): static;

/**
* Return the psr request.
Expand Down
Loading
Loading