Making Requests
Fetch PHP offers a one-request helper, a shared client facade, and a configurable handler.
Choose an entry point
fetch($url, $options)makes one request.fetch()with no URL returns the global handler for fluent configuration.fetch_client()returns the sharedFetch\Http\Clientfacade. It implements PSR-18 and also has convenience methods such asget()andpost().$client->getHandler()returns theFetch\Interfaces\ClientHandlercontract for handler-only configuration such aswithCache()andretry().- Pool and DNS configuration is deprecated since 4.1.0 and does not affect outgoing request transport. See HTTP/2 and legacy pool APIs.
Fetch\Http\ClientHandler::create()creates an independent handler;createWithBaseUri()andcreateWithClient()are factories.Fetch\Http\Client::createWithBaseUri()creates a client facade with a configured base URI.
Do not call handler-only methods directly on fetch_client(): it returns Client. Use fetch_client()->getHandler()->withCache(...) or instantiate a handler.
Common methods
The global helpers are get(), post(), put(), patch(), and delete(). The client and handler also support head() and options(). Use fetch($url, ['method' => 'TRACE']) or sendRequest() for the additional TRACE and CONNECT methods.
GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE, CONNECTget($url, $query) treats its second argument as query parameters. For the other global verb helpers, an array body is JSON by default. For an explicit method, use fetch() options.
Request configuration
Request options follow Guzzle's option names where applicable. Fetch-specific keys include base_uri, retries, retry_delay, retry_status_codes, retry_exceptions, cache, async, content_type, and token.
Common request options:
Option:
method- Meaning: HTTP method string or
Methodenum
- Meaning: HTTP method string or
Option:
headers- Meaning: Header name/value map
Option:
query- Meaning: Query parameter map, encoded by Guzzle
Option:
json- Meaning: JSON body; takes precedence over other body options
Option:
form/form_params- Meaning: URL-encoded form fields
Option:
multipart- Meaning: Multipart parts; Guzzle supplies the boundary
Option:
body- Meaning: String, stream, or other Guzzle-supported body
Option:
timeout- Meaning: Total request timeout, seconds; default 30
Option:
connect_timeout- Meaning: Connection timeout, seconds
Option:
allow_redirects- Meaning: Guzzle redirect policy
Option:
auth/token- Meaning: Basic auth credentials or bearer token
Option:
proxy,cookies,cert,ssl_key,verify- Meaning: Guzzle transport options; availability depends on entry point
For global fetch(), process_request_options() forwards the common options it explicitly normalizes. For lower-level Guzzle options such as verify, version, curl, sink, or decode_content, configure a ClientHandler or pass them through the Client facade.
Within one option set, body precedence is json > form/form_params > multipart > body. A body option from a later configuration scope replaces the earlier scope's body. The explicit content_type option overrides inferred content types; otherwise an explicit Content-Type header is preserved case-insensitively. Named json and form/form_params options determine serialization even when a custom Content-Type header is supplied; the header is sent as provided. The withBody(), request(), post(), put(), patch(), and delete() body-format argument also selects serialization independently of an explicit Content-Type header. A request-scope content_type option takes precedence over that argument. A generic array body passed to sendRequest() uses content_type or Content-Type to select its serialization. Multipart requests drop the caller's Content-Type so Guzzle can provide the boundary. Query parameters and other headers merge with handler defaults. Client::fetch() and the global base-URI helper pass request overrides through the immutable request context, so they do not persist into later requests or change the shared handler defaults.
<?php
declare(strict_types=1);
require dirname(__DIR__, 3).'/vendor/autoload.php';
use Fetch\Interfaces\Response as FetchResponse;
use Fetch\Testing\MockResponse;
use Fetch\Testing\MockServer;
MockServer::fake([
'GET https://api.example.test/v1/users*' => MockResponse::json([
['id' => 1, 'name' => 'Ada'],
]),
'POST https://api.example.test/v1/users' => MockResponse::created([
'id' => 2,
'name' => 'Grace',
]),
]);
MockServer::preventStrayRequests();
$usersResponse = get('https://api.example.test/v1/users', ['active' => true]);
if (! ($usersResponse instanceof FetchResponse)) {
throw new RuntimeException('The user request did not return a response.');
}
$users = $usersResponse->json();
$created = fetch('https://api.example.test/v1/users', [
'method' => 'POST',
'headers' => ['Accept' => 'application/json'],
'json' => ['name' => 'Grace'],
'timeout' => 5,
]);
if (
! ($created instanceof FetchResponse) ||
count($users) !== 1 ||
! $created->isCreated()
) {
throw new RuntimeException(
'The request examples returned unexpected responses.',
);
}Base URI and paths
A base URI must be an absolute valid URL. Relative request paths are resolved using Guzzle URI rules. To configure a reusable client:
<?php
declare(strict_types=1);
require dirname(__DIR__, 3).'/vendor/autoload.php';
use Fetch\Interfaces\Response as FetchResponse;
use Fetch\Testing\MockResponse;
use Fetch\Testing\MockServer;
MockServer::fake([
'GET https://api.example.test/v1/users' => MockResponse::json([
['id' => 1, 'name' => 'Ada'],
]),
]);
MockServer::preventStrayRequests();
$client = fetch_client(
[
'base_uri' => 'https://api.example.test/v1/',
'headers' => ['Accept' => 'application/json'],
'timeout' => 5,
],
reset: true,
);
$handler = $client->getHandler();
if ($handler->getOptions()['timeout'] !== 5) {
throw new RuntimeException('The client options were not applied.');
}
$handler->withHeader('X-Client', 'example');
$response = $handler->get('users');
if (! ($response instanceof FetchResponse) || ! $response->successful()) {
throw new RuntimeException('The configured client request failed.');
}Request objects
Fetch\Http\Request is an immutable PSR-7 request with factories such as Request::json(), Request::form(), Request::multipart() and verb factories. Send a PSR request through ClientInterface::sendRequest() when integrating with PSR-18. See the Request API.
Redirects, TLS, and proxies
Guzzle options pass through the Client or ClientHandler request path. Keep TLS verification enabled; provide verify, cert, and ssl_key only for explicit transport configuration. URI validation checks formatting, not whether a destination is a private or internal host. Apply SSRF controls in the application when URLs can come from untrusted input.
See authentication, file uploads, and the ClientHandler reference.