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