friendship ended with social-app. php is my new best friend
1--- 2title: Helper Functions 3description: Learn about the helper functions available in the Fetch HTTP package 4--- 5 6# Helper Functions 7 8The 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. 9 10## Main Functions 11 12### `fetch()` 13 14The primary helper function that mimics JavaScript's `fetch()` API. It provides a simple yet powerful way to make HTTP requests. 15 16```php 17function fetch( 18 string|RequestInterface|null $resource = null, 19 ?array $options = [] 20): ResponseInterface|ClientHandlerInterface|Client 21``` 22 23#### Parameters 24 25- `$resource`: A URL string, a `Request` object, or `null` to return the client for chaining 26- `$options`: An array of request options, including: 27 - `method`: HTTP method (string or `Method` enum) 28 - `headers`: Request headers (array) 29 - `body`: Request body (mixed) 30 - `json`: JSON data to send as body (array, takes precedence over body) 31 - `form`: Form data to send as body (array, takes precedence if no json) 32 - `multipart`: Multipart form data (array, takes precedence if no json/form) 33 - `query`: Query parameters (array) 34 - `base_uri`: Base URI (string) 35 - `timeout`: Request timeout in seconds (int) 36 - `retries`: Number of retries (int) 37 - `auth`: Basic auth credentials [username, password] (array) 38 - `token`: Bearer token (string) 39 - Plus other options like `proxy`, `cookies`, `allow_redirects`, etc. 40 41#### Return Value 42 43- If `$resource` is `null`: Returns the client instance for method chaining 44- If `$resource` is a URL string: Returns a `Response` object 45- If `$resource` is a `Request` object: Returns a `Response` object 46 47#### Examples 48 49Basic GET request: 50 51```php 52$response = fetch('https://api.example.com/users'); 53$users = $response->json(); 54``` 55 56POST request with JSON data: 57 58```php 59$response = fetch('https://api.example.com/users', [ 60 'method' => 'POST', 61 'json' => ['name' => 'John Doe', 'email' => 'john@example.com'] 62]); 63``` 64 65Setting headers: 66 67```php 68$response = fetch('https://api.example.com/users', [ 69 'headers' => [ 70 'Authorization' => 'Bearer token123', 71 'Accept' => 'application/json' 72 ] 73]); 74``` 75 76Using query parameters: 77 78```php 79$response = fetch('https://api.example.com/users', [ 80 'query' => ['page' => 1, 'per_page' => 20] 81]); 82``` 83 84Method chaining: 85 86```php 87fetch() 88 ->withToken('your-token') 89 ->withHeader('Accept', 'application/json') 90 ->get('https://api.example.com/users'); 91``` 92 93### `fetch_client()` 94 95Gets or configures the global fetch client instance. 96 97```php 98function fetch_client( 99 ?array $options = null, 100 bool $reset = false 101): Client 102``` 103 104#### Parameters 105 106- `$options`: Global client options 107- `$reset`: Whether to reset the client instance 108 109#### Return Value 110 111Returns the global `Client` instance. 112 113#### Examples 114 115Get the default client: 116 117```php 118$client = fetch_client(); 119``` 120 121Configure the global client: 122 123```php 124fetch_client([ 125 'base_uri' => 'https://api.example.com', 126 'timeout' => 10, 127 'headers' => [ 128 'User-Agent' => 'MyApp/1.0' 129 ] 130]); 131 132// Now all fetch() calls will use these settings by default 133$response = fetch('/users'); // Uses the base_uri 134``` 135 136Reset the client: 137 138```php 139fetch_client(reset: true); 140``` 141 142Add a logger: 143 144```php 145use Monolog\Logger; 146use Monolog\Handler\StreamHandler; 147 148$logger = new Logger('http'); 149$logger->pushHandler(new StreamHandler('logs/http.log', Logger::DEBUG)); 150 151// Set the logger on the client 152$client = fetch_client(); 153$client->setLogger($logger); 154``` 155 156## HTTP Method Helpers 157 158The package provides shorthand functions for common HTTP methods, making your code more concise and readable. 159 160### `get()` 161 162```php 163function get( 164 string $url, 165 ?array $query = null, 166 ?array $options = [] 167): ResponseInterface 168``` 169 170#### Examples 171 172Simple GET request: 173 174```php 175$response = get('https://api.example.com/users'); 176``` 177 178GET with query parameters: 179 180```php 181$response = get('https://api.example.com/users', [ 182 'page' => 1, 183 'per_page' => 20 184]); 185``` 186 187GET with additional options: 188 189```php 190$response = get('https://api.example.com/users', null, [ 191 'headers' => ['Accept' => 'application/json'], 192 'timeout' => 5 193]); 194``` 195 196### `post()` 197 198```php 199function post( 200 string $url, 201 mixed $data = null, 202 ?array $options = [] 203): ResponseInterface 204``` 205 206#### Examples 207 208POST with JSON data (arrays are automatically converted to JSON): 209 210```php 211$response = post('https://api.example.com/users', [ 212 'name' => 'John Doe', 213 'email' => 'john@example.com' 214]); 215``` 216 217POST with raw data: 218 219```php 220$response = post('https://api.example.com/webhook', 'Raw content', [ 221 'headers' => ['Content-Type' => 'text/plain'] 222]); 223``` 224 225POST with form data: 226 227```php 228$response = post('https://api.example.com/login', null, [ 229 'form' => [ 230 'username' => 'johndoe', 231 'password' => 'secret' 232 ] 233]); 234``` 235 236### `put()` 237 238```php 239function put( 240 string $url, 241 mixed $data = null, 242 ?array $options = [] 243): ResponseInterface 244``` 245 246#### Examples 247 248```php 249$response = put('https://api.example.com/users/123', [ 250 'name' => 'John Smith', 251 'email' => 'john.smith@example.com' 252]); 253``` 254 255### `patch()` 256 257```php 258function patch( 259 string $url, 260 mixed $data = null, 261 ?array $options = [] 262): ResponseInterface 263``` 264 265#### Examples 266 267```php 268$response = patch('https://api.example.com/users/123', [ 269 'status' => 'active' 270]); 271``` 272 273### `delete()` 274 275```php 276function delete( 277 string $url, 278 mixed $data = null, 279 ?array $options = [] 280): ResponseInterface 281``` 282 283#### Examples 284 285Simple DELETE: 286 287```php 288$response = delete('https://api.example.com/users/123'); 289``` 290 291DELETE with body: 292 293```php 294$response = delete('https://api.example.com/users/batch', [ 295 'ids' => [123, 456, 789] 296]); 297``` 298 299## Async/Promise Functions 300 301The Fetch PHP package includes a set of functions for working with asynchronous requests and promises. 302 303### `async()` 304 305Wraps a function to run asynchronously and returns a promise. 306 307```php 308function async(callable $fn): PromiseInterface 309``` 310 311#### Example 312 313```php 314$promise = async(function() { 315 return fetch('https://api.example.com/users'); 316}); 317``` 318 319### `await()` 320 321Waits for a promise to resolve and returns its value. 322 323```php 324function await(PromiseInterface $promise): mixed 325``` 326 327#### Example 328 329```php 330$response = await(async(function() { 331 return fetch('https://api.example.com/users'); 332})); 333 334$users = $response->json(); 335``` 336 337### `all()` 338 339Executes multiple promises concurrently and waits for all to complete. 340 341```php 342function all(array $promises): PromiseInterface 343``` 344 345#### Example 346 347```php 348$results = await(all([ 349 'users' => async(fn() => fetch('https://api.example.com/users')), 350 'posts' => async(fn() => fetch('https://api.example.com/posts')) 351])); 352 353$users = $results['users']->json(); 354$posts = $results['posts']->json(); 355``` 356 357### `race()` 358 359Executes multiple promises concurrently and returns the first to complete. 360 361```php 362function race(array $promises): PromiseInterface 363``` 364 365#### Example 366 367```php 368$response = await(race([ 369 async(fn() => fetch('https://api1.example.com/data')), 370 async(fn() => fetch('https://api2.example.com/data')) 371])); 372``` 373 374### `any()` 375 376Executes multiple promises concurrently and returns the first to succeed. 377 378```php 379function any(array $promises): PromiseInterface 380``` 381 382#### Example 383 384```php 385$response = await(any([ 386 async(fn() => fetch('https://api1.example.com/data')), 387 async(fn() => fetch('https://api2.example.com/data')) 388])); 389``` 390 391### `map()` 392 393Maps an array of items through an async function with controlled concurrency. 394 395```php 396function map(array $items, callable $callback, int $concurrency = 5): PromiseInterface 397``` 398 399#### Example 400 401```php 402$responses = await(map([1, 2, 3, 4, 5], function($id) { 403 return async(function() use ($id) { 404 return fetch("https://api.example.com/users/{$id}"); 405 }); 406}, 3)); // Process at most 3 items concurrently 407``` 408 409### `batch()` 410 411Processes items in batches with controlled concurrency. 412 413```php 414function batch( 415 array $items, 416 callable $callback, 417 int $batchSize = 10, 418 int $concurrency = 5 419): PromiseInterface 420``` 421 422#### Example 423 424```php 425$results = await(batch( 426 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 427 function($batch) { 428 return async(function() use ($batch) { 429 $results = []; 430 foreach ($batch as $id) { 431 $response = await(async(fn() => 432 fetch("https://api.example.com/users/{$id}") 433 )); 434 $results[] = $response->json(); 435 } 436 return $results; 437 }); 438 }, 439 3, // batch size 440 2 // concurrency 441)); 442``` 443 444### `retry()` 445 446Retries an async operation with exponential backoff. 447 448```php 449function retry( 450 callable $fn, 451 int $attempts = 3, 452 callable|int $delay = 100 453): PromiseInterface 454``` 455 456#### Example 457 458```php 459$response = await(retry( 460 function() { 461 return async(function() { 462 return fetch('https://api.example.com/unstable-endpoint'); 463 }); 464 }, 465 3, // max attempts 466 function($attempt) { 467 // Exponential backoff strategy 468 return min(pow(2, $attempt) * 100, 1000); 469 } 470)); 471``` 472 473## Using Helper Functions in Real-World Examples 474 475### Basic API Interaction 476 477```php 478// Fetch a list of users 479$users = get('https://api.example.com/users')->json(); 480 481// Create a new user 482$user = post('https://api.example.com/users', [ 483 'name' => 'John Doe', 484 'email' => 'john@example.com' 485])->json(); 486 487// Update a user 488$updatedUser = put("https://api.example.com/users/{$user['id']}", [ 489 'name' => 'John Smith' 490])->json(); 491 492// Delete a user 493delete("https://api.example.com/users/{$user['id']}"); 494``` 495 496### Authentication 497 498```php 499// Configure client with authentication 500fetch_client([ 501 'base_uri' => 'https://api.example.com', 502 'headers' => [ 503 'Authorization' => 'Bearer your-oauth-token' 504 ] 505]); 506 507// All requests now include authentication 508$response = get('/protected-resource'); 509 510// Or using the withToken method 511$response = fetch_client() 512 ->withToken('your-oauth-token') 513 ->get('/protected-resource'); 514 515// Basic authentication 516$response = fetch_client() 517 ->withAuth('username', 'password') 518 ->get('/protected-resource'); 519``` 520 521### File Upload 522 523```php 524$response = fetch('https://api.example.com/upload', [ 525 'method' => 'POST', 526 'multipart' => [ 527 [ 528 'name' => 'file', 529 'contents' => file_get_contents('/path/to/image.jpg'), 530 'filename' => 'upload.jpg', 531 'headers' => ['Content-Type' => 'image/jpeg'] 532 ], 533 [ 534 'name' => 'description', 535 'contents' => 'Profile picture' 536 ] 537 ] 538]); 539 540// Using the fluent interface 541$response = fetch_client() 542 ->withMultipart([ 543 [ 544 'name' => 'file', 545 'contents' => fopen('/path/to/image.jpg', 'r'), 546 'filename' => 'upload.jpg', 547 ], 548 [ 549 'name' => 'description', 550 'contents' => 'Profile picture' 551 ] 552 ]) 553 ->post('https://api.example.com/upload'); 554 555// Check if upload was successful 556if ($response->successful()) { 557 $fileUrl = $response->json()['url']; 558 echo "File uploaded successfully: {$fileUrl}"; 559} 560``` 561 562### Error Handling 563 564```php 565try { 566 $response = get('https://api.example.com/users/999'); 567 568 if ($response->isNotFound()) { 569 echo "User not found!"; 570 } elseif ($response->isUnauthorized()) { 571 echo "Authentication required!"; 572 } elseif ($response->failed()) { 573 echo "Request failed with status: " . $response->status(); 574 } else { 575 $user = $response->json(); 576 echo "Found user: " . $user['name']; 577 } 578} catch (\Fetch\Exceptions\NetworkException $e) { 579 echo "Network error: " . $e->getMessage(); 580} catch (\Fetch\Exceptions\RequestException $e) { 581 echo "Request error: " . $e->getMessage(); 582} catch (\Exception $e) { 583 echo "Error: " . $e->getMessage(); 584} 585``` 586 587### Parallel Requests with Modern Async/Await 588 589```php 590use function async; 591use function await; 592use function all; 593 594await(async(function() { 595 // Create multiple requests 596 $results = await(all([ 597 'users' => async(fn() => fetch('https://api.example.com/users')), 598 'posts' => async(fn() => fetch('https://api.example.com/posts')), 599 'comments' => async(fn() => fetch('https://api.example.com/comments')) 600 ])); 601 602 // Process the results 603 $users = $results['users']->json(); 604 $posts = $results['posts']->json(); 605 $comments = $results['comments']->json(); 606 607 echo "Fetched " . count($users) . " users, " . 608 count($posts) . " posts, and " . 609 count($comments) . " comments"; 610})); 611``` 612 613### Working with Content Types 614 615```php 616use Fetch\Enum\ContentType; 617 618// Using string content types 619$response = fetch_client() 620 ->withBody($data, 'application/json') 621 ->post('https://api.example.com/users'); 622 623// Using enum content types 624$response = fetch_client() 625 ->withBody($data, ContentType::JSON) 626 ->post('https://api.example.com/users'); 627 628// Checking content type 629if ($response->hasJsonContent()) { 630 $data = $response->json(); 631} elseif ($response->hasHtmlContent()) { 632 $html = $response->text(); 633} 634``` 635 636### Working with Enums 637 638```php 639use Fetch\Enum\Method; 640use Fetch\Enum\ContentType; 641use Fetch\Enum\Status; 642 643// Use method enum 644$response = fetch_client()->request(Method::POST, '/users', $userData); 645 646// Check status with enum 647if ($response->statusEnum() === Status::OK) { 648 // Process successful response 649} 650 651// Content type handling 652$response = fetch_client() 653 ->withBody($data, ContentType::JSON) 654 ->post('/users'); 655``` 656 657## Tips and Best Practices 658 6591. **Configure Once, Use Everywhere**: Use `fetch_client()` to set global options and defaults that will apply to all requests. 660 661 ```php 662 // Set up once at the beginning of your application 663 fetch_client([ 664 'base_uri' => 'https://api.example.com', 665 'timeout' => 10, 666 'headers' => [ 667 'User-Agent' => 'MyApp/1.0', 668 'Accept' => 'application/json' 669 ] 670 ]); 671 672 // Now use simplified calls throughout your code 673 $users = get('/users')->json(); 674 $user = get("/users/{$id}")->json(); 675 ``` 676 6772. **Use Type-Safe Enums**: Take advantage of PHP 8.1 enums for better type safety and code readability. 678 679 ```php 680 use Fetch\Enum\Method; 681 use Fetch\Enum\ContentType; 682 use Fetch\Enum\Status; 683 684 $response = fetch_client()->request(Method::POST, '/users', $userData); 685 686 if ($response->statusEnum() === Status::CREATED) { 687 // User was created successfully 688 } 689 ``` 690 6913. **Use the Right Helper for the Job**: Choose the appropriate helper function based on the HTTP method you need. 692 6934. **Handling JSON**: Arrays passed to `post()`, `put()`, `patch()`, and `delete()` are automatically treated as JSON data. 694 6955. **Leverage Method Chaining**: When you need more control, use the fluent interface: 696 697 ```php 698 fetch() 699 ->baseUri('https://api.example.com') 700 ->withToken('your-token') 701 ->timeout(5) 702 ->retry(3, 100) 703 ->get('/users'); 704 ``` 705 7066. **Use the Response Methods**: Take advantage of the response helper methods for cleaner code: 707 708 ```php 709 // Instead of: 710 if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) { 711 // ... 712 } 713 714 // Use: 715 if ($response->successful()) { 716 // ... 717 } 718 ``` 719 7207. **Modern Async/Await**: Use `async()` and `await()` for cleaner asynchronous code: 721 722 ```php 723 await(async(function() { 724 $response = await(async(fn() => fetch('https://api.example.com/users'))); 725 return $response->json(); 726 })); 727 ``` 728 7298. **Resource Conservation**: When working with many requests, use controlled concurrency with `map()` or `batch()`: 730 731 ```php 732 $results = await(map($items, function($item) { 733 return async(fn() => fetch("https://api.example.com/{$item}")); 734 }, 5)); // No more than 5 concurrent requests 735 ``` 736 737## Next Steps 738 739- Learn more about [Working with Responses](/guide/working-with-responses) 740- Explore [Asynchronous Requests](/guide/async-requests) for parallel HTTP operations 741- Discover [Retry Handling](/guide/retry-handling) for dealing with unreliable APIs 742- Learn about [Working with Enums](/guide/working-with-enums) for type-safe HTTP operations