Helper Functions
The Fetch HTTP package provides a set of global helper functions that offer a simpler, more direct way to make HTTP requests. These functions are designed to be familiar for developers who have experience with JavaScript's fetch API or other HTTP client libraries.
Main Functions
fetch()
The primary helper function that mimics JavaScript's fetch()
API. It provides a simple yet powerful way to make HTTP requests.
function fetch(
string|RequestInterface|null $resource = null,
?array $options = []
): ResponseInterface|ClientHandlerInterface|Client
Parameters
$resource
: A URL string, aRequest
object, ornull
to return the client for chaining$options
: An array of request options, including:method
: HTTP method (string orMethod
enum)headers
: Request headers (array)body
: Request body (mixed)json
: JSON data to send as body (array, takes precedence over body)form
: Form data to send as body (array, takes precedence if no json)multipart
: Multipart form data (array, takes precedence if no json/form)query
: Query parameters (array)base_uri
: Base URI (string)timeout
: Request timeout in seconds (int)retries
: Number of retries (int)auth
: Basic auth credentials [username, password] (array)token
: Bearer token (string)- Plus other options like
proxy
,cookies
,allow_redirects
, etc.
Return Value
- If
$resource
isnull
: Returns the client instance for method chaining - If
$resource
is a URL string: Returns aResponse
object - If
$resource
is aRequest
object: Returns aResponse
object
Examples
Basic GET request:
$response = fetch('https://api.example.com/users');
$users = $response->json();
POST request with JSON data:
$response = fetch('https://api.example.com/users', [
'method' => 'POST',
'json' => ['name' => 'John Doe', 'email' => 'john@example.com']
]);
Setting headers:
$response = fetch('https://api.example.com/users', [
'headers' => [
'Authorization' => 'Bearer token123',
'Accept' => 'application/json'
]
]);
Using query parameters:
$response = fetch('https://api.example.com/users', [
'query' => ['page' => 1, 'per_page' => 20]
]);
Method chaining:
fetch()
->withToken('your-token')
->withHeader('Accept', 'application/json')
->get('https://api.example.com/users');
fetch_client()
Gets or configures the global fetch client instance.
function fetch_client(
?array $options = null,
bool $reset = false
): Client
Parameters
$options
: Global client options$reset
: Whether to reset the client instance
Return Value
Returns the global Client
instance.
Examples
Get the default client:
$client = fetch_client();
Configure the global client:
fetch_client([
'base_uri' => 'https://api.example.com',
'timeout' => 10,
'headers' => [
'User-Agent' => 'MyApp/1.0'
]
]);
// Now all fetch() calls will use these settings by default
$response = fetch('/users'); // Uses the base_uri
Reset the client:
fetch_client(reset: true);
Add a logger:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('http');
$logger->pushHandler(new StreamHandler('logs/http.log', Logger::DEBUG));
// Set the logger on the client
$client = fetch_client();
$client->setLogger($logger);
HTTP Method Helpers
The package provides shorthand functions for common HTTP methods, making your code more concise and readable.
get()
function get(
string $url,
?array $query = null,
?array $options = []
): ResponseInterface
Examples
Simple GET request:
$response = get('https://api.example.com/users');
GET with query parameters:
$response = get('https://api.example.com/users', [
'page' => 1,
'per_page' => 20
]);
GET with additional options:
$response = get('https://api.example.com/users', null, [
'headers' => ['Accept' => 'application/json'],
'timeout' => 5
]);
post()
function post(
string $url,
mixed $data = null,
?array $options = []
): ResponseInterface
Examples
POST with JSON data (arrays are automatically converted to JSON):
$response = post('https://api.example.com/users', [
'name' => 'John Doe',
'email' => 'john@example.com'
]);
POST with raw data:
$response = post('https://api.example.com/webhook', 'Raw content', [
'headers' => ['Content-Type' => 'text/plain']
]);
POST with form data:
$response = post('https://api.example.com/login', null, [
'form' => [
'username' => 'johndoe',
'password' => 'secret'
]
]);
put()
function put(
string $url,
mixed $data = null,
?array $options = []
): ResponseInterface
Examples
$response = put('https://api.example.com/users/123', [
'name' => 'John Smith',
'email' => 'john.smith@example.com'
]);
patch()
function patch(
string $url,
mixed $data = null,
?array $options = []
): ResponseInterface
Examples
$response = patch('https://api.example.com/users/123', [
'status' => 'active'
]);
delete()
function delete(
string $url,
mixed $data = null,
?array $options = []
): ResponseInterface
Examples
Simple DELETE:
$response = delete('https://api.example.com/users/123');
DELETE with body:
$response = delete('https://api.example.com/users/batch', [
'ids' => [123, 456, 789]
]);
Async/Promise Functions
The Fetch PHP package includes a set of functions for working with asynchronous requests and promises.
async()
Wraps a function to run asynchronously and returns a promise.
function async(callable $fn): PromiseInterface
Example
$promise = async(function() {
return fetch('https://api.example.com/users');
});
await()
Waits for a promise to resolve and returns its value.
function await(PromiseInterface $promise): mixed
Example
$response = await(async(function() {
return fetch('https://api.example.com/users');
}));
$users = $response->json();
all()
Executes multiple promises concurrently and waits for all to complete.
function all(array $promises): PromiseInterface
Example
$results = await(all([
'users' => async(fn() => fetch('https://api.example.com/users')),
'posts' => async(fn() => fetch('https://api.example.com/posts'))
]));
$users = $results['users']->json();
$posts = $results['posts']->json();
race()
Executes multiple promises concurrently and returns the first to complete.
function race(array $promises): PromiseInterface
Example
$response = await(race([
async(fn() => fetch('https://api1.example.com/data')),
async(fn() => fetch('https://api2.example.com/data'))
]));
any()
Executes multiple promises concurrently and returns the first to succeed.
function any(array $promises): PromiseInterface
Example
$response = await(any([
async(fn() => fetch('https://api1.example.com/data')),
async(fn() => fetch('https://api2.example.com/data'))
]));
map()
Maps an array of items through an async function with controlled concurrency.
function map(array $items, callable $callback, int $concurrency = 5): PromiseInterface
Example
$responses = await(map([1, 2, 3, 4, 5], function($id) {
return async(function() use ($id) {
return fetch("https://api.example.com/users/{$id}");
});
}, 3)); // Process at most 3 items concurrently
batch()
Processes items in batches with controlled concurrency.
function batch(
array $items,
callable $callback,
int $batchSize = 10,
int $concurrency = 5
): PromiseInterface
Example
$results = await(batch(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
function($batch) {
return async(function() use ($batch) {
$results = [];
foreach ($batch as $id) {
$response = await(async(fn() =>
fetch("https://api.example.com/users/{$id}")
));
$results[] = $response->json();
}
return $results;
});
},
3, // batch size
2 // concurrency
));
retry()
Retries an async operation with exponential backoff.
function retry(
callable $fn,
int $attempts = 3,
callable|int $delay = 100
): PromiseInterface
Example
$response = await(retry(
function() {
return async(function() {
return fetch('https://api.example.com/unstable-endpoint');
});
},
3, // max attempts
function($attempt) {
// Exponential backoff strategy
return min(pow(2, $attempt) * 100, 1000);
}
));
Using Helper Functions in Real-World Examples
Basic API Interaction
// Fetch a list of users
$users = get('https://api.example.com/users')->json();
// Create a new user
$user = post('https://api.example.com/users', [
'name' => 'John Doe',
'email' => 'john@example.com'
])->json();
// Update a user
$updatedUser = put("https://api.example.com/users/{$user['id']}", [
'name' => 'John Smith'
])->json();
// Delete a user
delete("https://api.example.com/users/{$user['id']}");
Authentication
// Configure client with authentication
fetch_client([
'base_uri' => 'https://api.example.com',
'headers' => [
'Authorization' => 'Bearer your-oauth-token'
]
]);
// All requests now include authentication
$response = get('/protected-resource');
// Or using the withToken method
$response = fetch_client()
->withToken('your-oauth-token')
->get('/protected-resource');
// Basic authentication
$response = fetch_client()
->withAuth('username', 'password')
->get('/protected-resource');
File Upload
$response = fetch('https://api.example.com/upload', [
'method' => 'POST',
'multipart' => [
[
'name' => 'file',
'contents' => file_get_contents('/path/to/image.jpg'),
'filename' => 'upload.jpg',
'headers' => ['Content-Type' => 'image/jpeg']
],
[
'name' => 'description',
'contents' => 'Profile picture'
]
]
]);
// Using the fluent interface
$response = fetch_client()
->withMultipart([
[
'name' => 'file',
'contents' => fopen('/path/to/image.jpg', 'r'),
'filename' => 'upload.jpg',
],
[
'name' => 'description',
'contents' => 'Profile picture'
]
])
->post('https://api.example.com/upload');
// Check if upload was successful
if ($response->successful()) {
$fileUrl = $response->json()['url'];
echo "File uploaded successfully: {$fileUrl}";
}
Error Handling
try {
$response = get('https://api.example.com/users/999');
if ($response->isNotFound()) {
echo "User not found!";
} elseif ($response->isUnauthorized()) {
echo "Authentication required!";
} elseif ($response->failed()) {
echo "Request failed with status: " . $response->status();
} else {
$user = $response->json();
echo "Found user: " . $user['name'];
}
} catch (\Fetch\Exceptions\NetworkException $e) {
echo "Network error: " . $e->getMessage();
} catch (\Fetch\Exceptions\RequestException $e) {
echo "Request error: " . $e->getMessage();
} catch (\Exception $e) {
echo "Error: " . $e->getMessage();
}
Parallel Requests with Modern Async/Await
use function async;
use function await;
use function all;
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";
}));
Working with Content Types
use Fetch\Enum\ContentType;
// Using string content types
$response = fetch_client()
->withBody($data, 'application/json')
->post('https://api.example.com/users');
// Using enum content types
$response = fetch_client()
->withBody($data, ContentType::JSON)
->post('https://api.example.com/users');
// Checking content type
if ($response->hasJsonContent()) {
$data = $response->json();
} elseif ($response->hasHtmlContent()) {
$html = $response->text();
}
Working with Enums
use Fetch\Enum\Method;
use Fetch\Enum\ContentType;
use Fetch\Enum\Status;
// Use method enum
$response = fetch_client()->request(Method::POST, '/users', $userData);
// Check status with enum
if ($response->statusEnum() === Status::OK) {
// Process successful response
}
// Content type handling
$response = fetch_client()
->withBody($data, ContentType::JSON)
->post('/users');
Tips and Best Practices
Configure Once, Use Everywhere: Use
fetch_client()
to set global options and defaults that will apply to all requests.php// Set up once at the beginning of your application fetch_client([ 'base_uri' => 'https://api.example.com', 'timeout' => 10, 'headers' => [ 'User-Agent' => 'MyApp/1.0', 'Accept' => 'application/json' ] ]); // Now use simplified calls throughout your code $users = get('/users')->json(); $user = get("/users/{$id}")->json();
Use Type-Safe Enums: Take advantage of PHP 8.1 enums for better type safety and code readability.
phpuse Fetch\Enum\Method; use Fetch\Enum\ContentType; use Fetch\Enum\Status; $response = fetch_client()->request(Method::POST, '/users', $userData); if ($response->statusEnum() === Status::CREATED) { // User was created successfully }
Use the Right Helper for the Job: Choose the appropriate helper function based on the HTTP method you need.
Handling JSON: Arrays passed to
post()
,put()
,patch()
, anddelete()
are automatically treated as JSON data.Leverage Method Chaining: When you need more control, use the fluent interface:
phpfetch() ->baseUri('https://api.example.com') ->withToken('your-token') ->timeout(5) ->retry(3, 100) ->get('/users');
Use the Response Methods: Take advantage of the response helper methods for cleaner code:
php// Instead of: if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) { // ... } // Use: if ($response->successful()) { // ... }
Modern Async/Await: Use
async()
andawait()
for cleaner asynchronous code:phpawait(async(function() { $response = await(async(fn() => fetch('https://api.example.com/users'))); return $response->json(); }));
Resource Conservation: When working with many requests, use controlled concurrency with
map()
orbatch()
:php$results = await(map($items, function($item) { return async(fn() => fetch("https://api.example.com/{$item}")); }, 5)); // No more than 5 concurrent requests
Next Steps
- Learn more about Working with Responses
- Explore Asynchronous Requests for parallel HTTP operations
- Discover Retry Handling for dealing with unreliable APIs
- Learn about Working with Enums for type-safe HTTP operations