Fetch HTTP Package - Overview
Introduction
The Fetch HTTP package provides a modern, flexible HTTP client for PHP applications, bringing JavaScript's fetch
API experience to PHP. It features a fluent interface, extensive configuration options, and robust error handling, making it ideal for consuming APIs and working with web services.
Key Components
The package is comprised of several main components:
Client
The Client
class is a high-level wrapper that:
- Implements PSR-18 ClientInterface for standardized HTTP client behavior
- Implements PSR-3 LoggerAwareInterface for easy integration with logging systems
- Provides a simple fetch-style API similar to JavaScript's fetch API
- Handles error conversion to specific exception types
ClientHandler
The ClientHandler
class is a more powerful, configurable implementation that:
- Offers a fluent, chainable API for request building
- Provides extensive configuration options for request customization
- Supports both synchronous and asynchronous requests
- Implements retry logic with exponential backoff
- Offers promise-based operations for complex async workflows
Response
The Response
class extends PSR-7 ResponseInterface and provides:
- Rich methods for working with HTTP responses
- Status code helpers like
isOk()
,isNotFound()
, etc. - Content type inspection with
hasJsonContent()
,hasHtmlContent()
, etc. - Convenient data access methods like
json()
,text()
,array()
,object()
- Array access interface for working with JSON responses
Enums
Type-safe PHP 8.1 enums for HTTP concepts:
Method
: HTTP methods (GET, POST, PUT, etc.)ContentType
: Content types with helpers likeisJson()
,isText()
Status
: HTTP status codes with helpers likeisSuccess()
,isClientError()
Feature Highlights
- JavaScript-like API: Familiar syntax for developers coming from JavaScript
- PSR Compatibility: Implements PSR-18 (HTTP Client), PSR-7 (HTTP Messages), and PSR-3 (Logger)
- Fluent Interface: Chain method calls for clean, readable code
- Type-Safe Enums: Modern PHP 8.1 enums for HTTP methods, content types, and status codes
- Flexible Authentication: Support for Bearer tokens, Basic auth, and more
- Logging: Comprehensive request/response logging with sanitization of sensitive data
- Retries: Configurable retry logic with exponential backoff and jitter
- Asynchronous Requests: Promise-based async operations with concurrency control
- Content Type Handling: Simplified handling of JSON, forms, multipart data, etc.
- Testing Utilities: Built-in mock response helpers for testing
Architecture
+------------------+ | Client | <-- High-level API (PSR-18 compliant) +------------------+ | v +------------------+ | ClientHandler | <-- Core implementation with advanced features +------------------+ | +-----------+ | Traits | <-- Functionality separated into focused traits +-----------+ | ConfiguresRequests | HandlesUris | ManagesPromises | ManagesRetries | PerformsHttpRequests +-----------+ | v +------------------+ | Response | <-- Enhanced response handling +------------------+ | v +------------------+ | Guzzle Client | <-- Underlying HTTP client implementation +------------------+
Usage Patterns
Simple Usage
// Global helper functions for quick requests $response = fetch('https://api.example.com/users'); $users = $response->json(); // HTTP method-specific helpers $user = post('https://api.example.com/users', [ 'name' => 'John Doe', 'email' => 'john@example.com' ])->json();
Advanced Configuration
The ClientHandler
class offers more control and customization options for advanced use cases:
use Fetch\Http\ClientHandler; $handler = new ClientHandler(); $response = $handler ->withToken('your-api-token') ->withHeaders(['Accept' => 'application/json']) ->withQueryParameters(['page' => 1, 'limit' => 10]) ->timeout(5) ->retry(3, 100) ->get('https://api.example.com/users');
Type-Safe Enums
use Fetch\Enum\Method; use Fetch\Enum\ContentType; use Fetch\Enum\Status; // Use enums for HTTP methods $client = fetch_client(); $response = $client->request(Method::POST, '/users', $userData); // Check HTTP status with enums if ($response->statusEnum() === Status::OK) { // Process successful response } // Content type handling $response = $client->withBody($data, ContentType::JSON)->post('/users');
Asynchronous Requests
For handling multiple requests efficiently:
use function async; use function await; use function all; // Execute an async function await(async(function() { // Create multiple requests $results = await(all([ 'users' => async(fn() => fetch('https://api.example.com/users')), 'posts' => async(fn() => fetch('https://api.example.com/posts')), 'comments' => async(fn() => fetch('https://api.example.com/comments')) ])); // Process the results $users = $results['users']->json(); $posts = $results['posts']->json(); $comments = $results['comments']->json(); echo "Fetched " . count($users) . " users, " . count($posts) . " posts, and " . count($comments) . " comments"; }));
Global Client Configuration
// Configure once at application bootstrap fetch_client([ 'base_uri' => 'https://api.example.com', 'headers' => [ 'User-Agent' => 'MyApp/1.0', 'Accept' => 'application/json', ], 'timeout' => 10, ]); // Use the configured client throughout your application function getUserData($userId) { return fetch_client()->get("/users/{$userId}")->json(); } function createUser($userData) { return fetch_client()->post('/users', $userData)->json(); }
Enhanced Response Handling
$response = fetch('https://api.example.com/users/1'); // Status code helpers if ($response->isOk()) { // Handle 200 OK } else if ($response->isNotFound()) { // Handle 404 Not Found } else if ($response->isUnauthorized()) { // Handle 401 Unauthorized } // Status category helpers if ($response->successful()) { // Handle any 2xx status } else if ($response->isClientError()) { // Handle any 4xx status } else if ($response->isServerError()) { // Handle any 5xx status } // Content type helpers if ($response->hasJsonContent()) { $data = $response->json(); } else if ($response->hasHtmlContent()) { $html = $response->text(); } // Array access for JSON responses $user = $response['user']; $name = $response['user']['name'];
When to Use Each Class
Use Client
when
- You need PSR-18 compatibility
- You prefer a simpler API similar to JavaScript's fetch
- You're working within a framework that expects a PSR-18 client
- You want built-in exception handling for network and HTTP errors
Use ClientHandler
when
- You need advanced configuration options
- You want to use asynchronous requests and promises
- You need fine-grained control over retries and timeouts
- You're performing complex operations like concurrent requests
Use global helpers (fetch()
, get()
, post()
, etc.) when
- You're making simple, one-off requests
- You don't need extensive configuration
- You want the most concise, readable code
Exception Handling
The package provides several exception types for different error scenarios:
NetworkException
: For connection and network-related errorsRequestException
: For HTTP request errorsClientException
: For unexpected client errorsTimeoutException
: For request timeouts
Each exception provides context about the failed request to aid in debugging and error handling.