jerome / fetch-php
The JavaScript fetch API for PHP.
Fund package maintenance!
thavarshan
Buy Me A Coffee
Installs: 3 445
Dependents: 3
Suggesters: 0
Security: 0
Stars: 384
Watchers: 6
Forks: 20
Open Issues: 2
Requires
- php: ^8.0
- guzzlehttp/guzzle: ^7.9
- guzzlehttp/psr7: ^2.7
- jerome/matrix: ^3.2
- psr/http-message: ^1.0|^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- laravel/pint: ^1.21
- mockery/mockery: ^1.6
- pestphp/pest: ^2.0|^3.0
- phpstan/phpstan: ^1.11.5
- squizlabs/php_codesniffer: ^3.7
- symfony/var-dumper: ^6.0|^7.2
- tightenco/duster: ^3.2
This package is auto-updated.
Last update: 2025-05-05 02:53:44 UTC
README
Fetch PHP
Fetch PHP is a modern HTTP client library for PHP that brings JavaScript's fetch
API experience to PHP. Built on top of Guzzle and powered by the Matrix package for true asynchronous capabilities using ReactPHP, Fetch PHP allows you to write asynchronous HTTP code with a clean, intuitive JavaScript-like syntax.
With support for both synchronous and asynchronous requests, a fluent chainable API, and powerful retry mechanics, Fetch PHP streamlines HTTP operations in your PHP applications.
Make sure to check out Matrix for more information on how Fetch PHP is powered by ReactPHP.
Full documentation can be found here
Key Features
- JavaScript-like Syntax: Write HTTP requests just like you would in JavaScript with the
fetch()
function - True Async with ReactPHP: Leverage ReactPHP for non-blocking I/O
- Promise-based API: Use familiar
.then()
and.catch()
methods for async operations - Fluent Interface: Build requests with a clean, chainable API
- Built on Guzzle: Benefit from Guzzle's robust functionality with a more elegant API
- Retry Mechanics: Automatically retry failed requests with exponential backoff
Why Choose Fetch PHP?
Beyond Guzzle
While Guzzle is a powerful HTTP client, Fetch PHP enhances the experience by providing:
- True async with ReactPHP: Unlike Guzzle's Promise-based concurrency, Fetch PHP uses ReactPHP for genuine asynchronous operations
- JavaScript-like API: Enjoy the familiar
async
/await
pattern from JavaScript - Task Lifecycle Management: Start, pause, resume, cancel, and retry tasks with fine-grained control
- Simplified Error Handling: Handle errors more elegantly with promise-based callbacks
Feature | Fetch PHP | Guzzle |
---|---|---|
Async Operations | True async with ReactPHP | Promise-based concurrency |
API Style | JavaScript-like fetch + async/await | PHP-style Promises |
Task Control | Full lifecycle management | Limited to Promise chains |
Error Handling | Customizable error handlers | Standard Promise rejection |
Syntax | Clean, minimal | More verbose |
Installation
composer require jerome/fetch-php
Requirements: PHP 8.1 or higher
Basic Usage
Synchronous Requests
// Simple GET request $response = fetch('https://api.example.com/users'); $users = $response->json(); // POST request with JSON body $response = fetch('https://api.example.com/users', [ 'method' => 'POST', 'headers' => ['Content-Type' => 'application/json'], 'body' => ['name' => 'John Doe', 'email' => 'john@example.com'], ]);
Asynchronous Requests
use function async; use function await; use Fetch\Interfaces\Response as ResponseInterface; // Using Promise-style chaining async(fn () => fetch('https://api.example.com/users')) ->then(fn (ResponseInterface $response) => $response->json()) ->catch(fn (\Throwable $e) => print "Error: " . $e->getMessage()); // Using async/await syntax try { $response = await(async(fn () => fetch('https://api.example.com/users'))); $users = $response->json(); } catch (\Throwable $e) { echo 'Error: ' . $e->getMessage(); }
Fluent API
// Chain methods to build your request $response = fetch() ->baseUri('https://api.example.com') ->withHeaders(['Accept' => 'application/json']) ->withToken('your-auth-token') ->withQueryParameters(['page' => 1, 'limit' => 10]) ->get('/users'); // Async with fluent API async(fn () => fetch() ->baseUri('https://api.example.com') ->withBody(['name' => 'John Doe']) ->post('/users')) ->then(fn ($response) => $response->json());
Advanced Usage
Concurrent Requests
use function all; use function await; use function async; // Prepare multiple async requests $userPromise = async(fn () => fetch('https://api.example.com/users')); $postsPromise = async(fn () => fetch('https://api.example.com/posts')); $commentsPromise = async(fn () => fetch('https://api.example.com/comments')); // Wait for all to complete $results = await(all([ 'users' => $userPromise, 'posts' => $postsPromise, 'comments' => $commentsPromise ])); // Access results $users = $results['users']->json(); $posts = $results['posts']->json(); $comments = $results['comments']->json();
Task Lifecycle Management
use Task; use Enum\TaskStatus; // Create a task for a request $task = async(fn () => fetch('https://api.example.com/large-dataset')); // Start the task $task->start(); // Check the task status if ($task->getStatus() === TaskStatus::RUNNING) { // You can pause the task if needed $task->pause(); // And resume it later $task->resume(); } // Cancel the task if needed $task->cancel(); // Retry the task if it failed if ($task->getStatus() === TaskStatus::FAILED) { $task->retry(); } // Get the result when complete if ($task->getStatus() === TaskStatus::COMPLETED) { $response = $task->getResult(); $data = $response->json(); }
Configuring Retries
// Retry up to 3 times with a 100ms delay between retries $response = fetch('https://api.example.com/unstable-endpoint', [ 'retries' => 3, 'retry_delay' => 100 ]); // Or with fluent API $response = fetch() ->retry(3, 100) ->get('https://api.example.com/unstable-endpoint');
Working with Responses
$response = fetch('https://api.example.com/users/1'); // Check if request was successful if ($response->ok()) { // HTTP status code echo $response->status(); // 200 // Response body as JSON $user = $response->json(); // Response body as string $body = $response->body(); // Get a specific header $contentType = $response->header('Content-Type'); }
Advanced Configuration
Authentication
// Basic auth $response = fetch('https://api.example.com/secure', [ 'auth' => ['username', 'password'] ]); // Bearer token $response = fetch() ->withToken('your-oauth-token') ->get('https://api.example.com/secure');
Proxies
$response = fetch('https://api.example.com', [ 'proxy' => 'http://proxy.example.com:8080' ]); // Or with fluent API $response = fetch() ->withProxy('http://proxy.example.com:8080') ->get('https://api.example.com');
Error Handling
// Synchronous error handling try { $response = fetch('https://api.example.com/nonexistent'); if ($response->failed()) { echo "Request failed with status: " . $response->status(); } } catch (\Throwable $e) { echo "Exception: " . $e->getMessage(); } // Asynchronous error handling async(fn () => fetch('https://api.example.com/nonexistent')) ->then(function ($response) { if ($response->ok()) { return $response->json(); } throw new \Exception("Request failed with status: " . $response->status()); }) ->catch(function (\Throwable $e) { echo "Error: " . $e->getMessage(); // You could retry the request here return retry(); });
License
This project is licensed under the MIT License - see the LICENSE.md file for details.
Contributing
Contributions are welcome! We're currently looking for help with:
- Expanding test coverage
- Improving documentation
- Adding support for additional HTTP features
To contribute:
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/amazing-feature
) - Commit your Changes (
git commit -m 'Add some amazing-feature'
) - Push to the Branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Acknowledgments
- Thanks to Guzzle HTTP for providing the underlying HTTP client
- Thanks to all contributors who have helped improve this package