friendship ended with social-app. php is my new best friend
1---
2title: Making Requests
3description: Learn how to make HTTP requests using the Fetch HTTP package
4---
5
6# Making Requests
7
8This guide covers different ways to make HTTP requests using the Fetch HTTP package, including the helper functions and the object-oriented interface.
9
10## Using Helper Functions
11
12The simplest way to make requests is using the global helper functions.
13
14### The `fetch()` Function
15
16The `fetch()` function is the primary way to make HTTP requests:
17
18```php
19// Simple GET request
20$response = fetch('https://api.example.com/users');
21
22// POST request with JSON data
23$response = fetch('https://api.example.com/users', [
24 'method' => 'POST',
25 'json' => ['name' => 'John Doe', 'email' => 'john@example.com']
26]);
27```
28
29### HTTP Method Helpers
30
31For common HTTP methods, you can use the dedicated helper functions:
32
33```php
34// GET request
35$response = get('https://api.example.com/users');
36
37// POST request
38$response = post('https://api.example.com/users', [
39 'name' => 'John Doe',
40 'email' => 'john@example.com'
41]);
42
43// PUT request
44$response = put('https://api.example.com/users/123', [
45 'name' => 'John Smith',
46 'email' => 'john.smith@example.com'
47]);
48
49// PATCH request
50$response = patch('https://api.example.com/users/123', [
51 'status' => 'active'
52]);
53
54// DELETE request
55$response = delete('https://api.example.com/users/123');
56```
57
58## Using the Object-Oriented Interface
59
60For more control and reusability, you can use the object-oriented interface.
61
62### Using the Client Class
63
64The `Client` class provides a high-level interface:
65
66```php
67use Fetch\Http\Client;
68
69$client = new Client();
70
71// Make requests
72$response = $client->get('https://api.example.com/users');
73$response = $client->post('https://api.example.com/users', [
74 'name' => 'John Doe',
75 'email' => 'john@example.com'
76]);
77```
78
79### Using the ClientHandler Class
80
81The `ClientHandler` class offers a fluent, chainable API with more options:
82
83```php
84use Fetch\Http\ClientHandler;
85
86$handler = new ClientHandler();
87
88// Configure and make a request
89$response = $handler
90 ->withHeaders([
91 'Accept' => 'application/json',
92 'X-API-Key' => 'your-api-key'
93 ])
94 ->withToken('your-oauth-token')
95 ->get('https://api.example.com/users');
96```
97
98### Factory Methods
99
100You can also use static factory methods to create preconfigured clients:
101
102```php
103// Create with base URI
104$client = ClientHandler::createWithBaseUri('https://api.example.com');
105$response = $client->get('/users'); // Uses the base URI
106
107// Create with custom Guzzle client
108$guzzleClient = new \GuzzleHttp\Client([
109 'timeout' => 30,
110 'verify' => false, // Disable SSL verification (not recommended for production)
111]);
112$client = ClientHandler::createWithClient($guzzleClient);
113```
114
115## Request Configuration Options
116
117Whether you use the helper functions or the object-oriented interface, you can configure various aspects of your requests.
118
119### Headers
120
121```php
122// Using fetch()
123$response = fetch('https://api.example.com/users', [
124 'headers' => [
125 'Accept' => 'application/json',
126 'User-Agent' => 'MyApp/1.0',
127 'X-Custom-Header' => 'value'
128 ]
129]);
130
131// Using ClientHandler
132$response = ClientHandler::create()
133 ->withHeader('Accept', 'application/json')
134 ->withHeader('User-Agent', 'MyApp/1.0')
135 ->withHeader('X-Custom-Header', 'value')
136 ->get('https://api.example.com/users');
137
138// Setting multiple headers at once
139$response = ClientHandler::create()
140 ->withHeaders([
141 'Accept' => 'application/json',
142 'User-Agent' => 'MyApp/1.0',
143 'X-Custom-Header' => 'value'
144 ])
145 ->get('https://api.example.com/users');
146```
147
148### Query Parameters
149
150```php
151// Using fetch()
152$response = fetch('https://api.example.com/users', [
153 'query' => [
154 'page' => 1,
155 'per_page' => 20,
156 'sort' => 'created_at',
157 'order' => 'desc'
158 ]
159]);
160
161// Using get() with query params as second argument
162$response = get('https://api.example.com/users', [
163 'page' => 1,
164 'per_page' => 20
165]);
166
167// Using ClientHandler
168$response = ClientHandler::create()
169 ->withQueryParameter('page', 1)
170 ->withQueryParameter('per_page', 20)
171 ->withQueryParameter('sort', 'created_at')
172 ->withQueryParameter('order', 'desc')
173 ->get('https://api.example.com/users');
174
175// Setting multiple query parameters at once
176$response = ClientHandler::create()
177 ->withQueryParameters([
178 'page' => 1,
179 'per_page' => 20,
180 'sort' => 'created_at',
181 'order' => 'desc'
182 ])
183 ->get('https://api.example.com/users');
184```
185
186### Request Body
187
188#### JSON
189
190```php
191// Using fetch()
192$response = fetch('https://api.example.com/users', [
193 'method' => 'POST',
194 'json' => [
195 'name' => 'John Doe',
196 'email' => 'john@example.com',
197 'roles' => ['editor', 'admin']
198 ]
199]);
200
201// Using post() helper (arrays are automatically sent as JSON)
202$response = post('https://api.example.com/users', [
203 'name' => 'John Doe',
204 'email' => 'john@example.com',
205 'roles' => ['editor', 'admin']
206]);
207
208// Using ClientHandler
209$response = ClientHandler::create()
210 ->withJson([
211 'name' => 'John Doe',
212 'email' => 'john@example.com',
213 'roles' => ['editor', 'admin']
214 ])
215 ->post('https://api.example.com/users');
216```
217
218#### Form Data
219
220```php
221// Using fetch()
222$response = fetch('https://api.example.com/login', [
223 'method' => 'POST',
224 'form' => [
225 'username' => 'johndoe',
226 'password' => 'secret',
227 'remember' => true
228 ]
229]);
230
231// Using ClientHandler
232$response = ClientHandler::create()
233 ->withFormParams([
234 'username' => 'johndoe',
235 'password' => 'secret',
236 'remember' => true
237 ])
238 ->post('https://api.example.com/login');
239```
240
241#### Multipart Form Data (File Uploads)
242
243```php
244// Using fetch()
245$response = fetch('https://api.example.com/upload', [
246 'method' => 'POST',
247 'multipart' => [
248 [
249 'name' => 'file',
250 'contents' => file_get_contents('/path/to/image.jpg'),
251 'filename' => 'upload.jpg',
252 'headers' => ['Content-Type' => 'image/jpeg']
253 ],
254 [
255 'name' => 'description',
256 'contents' => 'Profile picture'
257 ]
258 ]
259]);
260
261// Using ClientHandler
262$response = ClientHandler::create()
263 ->withMultipart([
264 [
265 'name' => 'file',
266 'contents' => fopen('/path/to/image.jpg', 'r'),
267 'filename' => 'upload.jpg',
268 ],
269 [
270 'name' => 'description',
271 'contents' => 'Profile picture'
272 ]
273 ])
274 ->post('https://api.example.com/upload');
275```
276
277#### Raw Body
278
279```php
280// Using fetch()
281$response = fetch('https://api.example.com/webhook', [
282 'method' => 'POST',
283 'body' => 'Raw request content',
284 'headers' => ['Content-Type' => 'text/plain']
285]);
286
287// Using ClientHandler with string body
288$response = ClientHandler::create()
289 ->withBody('Raw request content', 'text/plain')
290 ->post('https://api.example.com/webhook');
291
292// Using ClientHandler with body and content type enum
293use Fetch\Enum\ContentType;
294$response = ClientHandler::create()
295 ->withBody('<user><name>John</name></user>', ContentType::XML)
296 ->post('https://api.example.com/users');
297```
298
299### Timeouts
300
301```php
302// Using fetch()
303$response = fetch('https://api.example.com/slow-resource', [
304 'timeout' => 30 // 30 seconds
305]);
306
307// Using ClientHandler
308$response = ClientHandler::create()
309 ->timeout(30)
310 ->get('https://api.example.com/slow-resource');
311```
312
313### Retries
314
315```php
316// Using fetch()
317$response = fetch('https://api.example.com/flaky-resource', [
318 'retries' => 3,
319 'retry_delay' => 100 // 100ms initial delay with exponential backoff
320]);
321
322// Using ClientHandler
323$response = ClientHandler::create()
324 ->retry(3, 100) // 3 retries with 100ms initial delay
325 ->retryStatusCodes([408, 429, 500, 502, 503, 504]) // Customize retryable status codes
326 ->retryExceptions(['GuzzleHttp\Exception\ConnectException']) // Customize retryable exceptions
327 ->get('https://api.example.com/flaky-resource');
328```
329
330### Base URI
331
332```php
333// Using fetch()
334$response = fetch('/users', [
335 'base_uri' => 'https://api.example.com'
336]);
337
338// Using ClientHandler
339$client = ClientHandler::createWithBaseUri('https://api.example.com');
340$response = $client->get('/users');
341$anotherResponse = $client->get('/posts');
342```
343
344### Working with Enums
345
346```php
347use Fetch\Enum\Method;
348use Fetch\Enum\ContentType;
349
350// Use method enum
351$response = ClientHandler::create()
352 ->request(Method::POST, 'https://api.example.com/users', [
353 'name' => 'John Doe',
354 'email' => 'john@example.com'
355 ]);
356
357// Use content type enum
358$response = ClientHandler::create()
359 ->withBody('{"name":"John Doe"}', ContentType::JSON)
360 ->post('https://api.example.com/users');
361```
362
363## Reusing Configuration
364
365One of the advantages of the object-oriented interface is the ability to reuse configuration.
366
367### Reusing a Client
368
369```php
370$client = ClientHandler::createWithBaseUri('https://api.example.com')
371 ->withToken('your-oauth-token')
372 ->withHeader('Accept', 'application/json');
373
374// Use the same configuration for multiple requests
375$users = $client->get('/users')->json();
376$user = $client->get("/users/{$id}")->json();
377$posts = $client->get('/posts')->json();
378```
379
380### Cloning with Modified Options
381
382```php
383// Create a base client
384$baseClient = ClientHandler::createWithBaseUri('https://api.example.com')
385 ->withHeaders([
386 'User-Agent' => 'MyApp/1.0',
387 'Accept' => 'application/json'
388 ]);
389
390// Create a clone with auth for protected endpoints
391$authClient = $baseClient->withClonedOptions([
392 'headers' => [
393 'Authorization' => 'Bearer ' . $token
394 ]
395]);
396
397// Another clone with different timeout
398$longTimeoutClient = $baseClient->withClonedOptions([
399 'timeout' => 60
400]);
401
402// Use the clients
403$publicData = $baseClient->get('/public-data')->json();
404$privateData = $authClient->get('/private-data')->json();
405$largeReport = $longTimeoutClient->get('/large-report')->json();
406```
407
408## Setting Global Defaults
409
410```php
411// Set default options for all new ClientHandler instances
412ClientHandler::setDefaultOptions([
413 'timeout' => 15,
414 'headers' => [
415 'User-Agent' => 'MyApp/1.0',
416 'Accept' => 'application/json'
417 ]
418]);
419
420// Set up a global client configuration
421fetch_client([
422 'base_uri' => 'https://api.example.com',
423 'headers' => [
424 'User-Agent' => 'MyApp/1.0'
425 ],
426 'timeout' => 10
427]);
428
429// Now simple helper functions will use this configuration
430$users = get('/users')->json();
431```
432
433## Logging
434
435The Fetch PHP package supports PSR-3 logging:
436
437```php
438use Monolog\Logger;
439use Monolog\Handler\StreamHandler;
440
441// Create a logger
442$logger = new Logger('fetch');
443$logger->pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG));
444
445// Set the logger on the client
446$client = fetch_client();
447$client->setLogger($logger);
448
449// Or set it on the handler
450$handler = fetch_client()->getHandler();
451$handler->setLogger($logger);
452
453// Now all requests and responses will be logged
454$response = get('https://api.example.com/users');
455```
456
457## Creating Mock Responses (For Testing)
458
459```php
460use Fetch\Http\ClientHandler;
461
462// Create a simple mock response
463$mockResponse = ClientHandler::createMockResponse(
464 statusCode: 200,
465 headers: ['Content-Type' => 'application/json'],
466 body: '{"name": "John", "email": "john@example.com"}'
467);
468
469// Create a JSON mock response
470$mockJsonResponse = ClientHandler::createJsonResponse(
471 data: ['name' => 'John', 'email' => 'john@example.com'],
472 statusCode: 200
473);
474```
475
476## PSR-7 and PSR-18 Compatibility
477
478The package implements PSR-7 and PSR-18 interfaces, making it compatible with other PSR-7 HTTP clients and middleware:
479
480```php
481// Create a PSR-7 request
482use GuzzleHttp\Psr7\Request;
483$request = new Request('GET', 'https://api.example.com/users', [
484 'Accept' => 'application/json'
485]);
486
487// Use with any PSR-18 client
488$psr18Client = new SomePsr18Client();
489$response = $psr18Client->sendRequest($request);
490
491// Our Client class is PSR-18 compatible
492$client = new \Fetch\Http\Client();
493$response = $client->sendRequest($request);
494```
495
496## Error Handling
497
498```php
499try {
500 $response = fetch('https://api.example.com/users/999');
501
502 if ($response->failed()) {
503 echo "Request failed with status: " . $response->status();
504 }
505} catch (\Fetch\Exceptions\NetworkException $e) {
506 echo "Network error: " . $e->getMessage();
507} catch (\Fetch\Exceptions\RequestException $e) {
508 echo "Request error: " . $e->getMessage();
509} catch (\Fetch\Exceptions\ClientException $e) {
510 echo "Client error: " . $e->getMessage();
511} catch (\Exception $e) {
512 echo "Error: " . $e->getMessage();
513}
514```
515
516## Next Steps
517
518- Learn more about [Working with Responses](/guide/working-with-responses)
519- Explore [Authentication](/guide/authentication) options
520- Discover [Asynchronous Requests](/guide/async-requests)
521- Learn about [Working with Enums](/guide/working-with-enums) for type-safe HTTP operations