-
Notifications
You must be signed in to change notification settings - Fork 0
HttpClient
Ray Fung edited this page Feb 26, 2026
·
3 revisions
Razy's HttpClient provides a fluent, cURL-based HTTP client for making external API requests. It supports JSON/form/multipart encoding, authentication, retries, timeouts, and request/response hooks.
- Quick Start
- Creating a Client
- Configuration
- Making Requests
- Handling Responses
- Hooks
- Full Example
- API Reference
use Razy\Http\HttpClient;
$response = HttpClient::create()
->baseUrl('https://api.example.com')
->withToken('my-api-key')
->asJson()
->get('/users');
$users = $response->json();// Static factory
$client = HttpClient::create();
// Pre-configured for an API
$api = HttpClient::create()
->baseUrl('https://api.example.com/v2')
->withToken('secret-token')
->asJson()
->timeout(10);All configuration methods return $this for fluent chaining.
$client->baseUrl('https://api.example.com/v2');
// Requests use relative paths
$client->get('/users'); // → https://api.example.com/v2/users
$client->get('/users/42'); // → https://api.example.com/v2/users/42// Set multiple headers
$client->withHeaders([
'Accept' => 'application/json',
'X-Request-Id' => 'abc-123',
]);
// Set a single header
$client->withHeader('X-Custom', 'value');// Bearer token
$client->withToken('eyJhbGciOiJIUzI1NiIs...');
// → Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
// Basic auth
$client->withBasicAuth('username', 'password');
// → Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=$client->timeout(30); // Total request timeout (seconds)
$client->connectTimeout(5); // Connection timeout (seconds)// Disable SSL verification (development only!)
$client->withoutVerifying();// JSON (Content-Type: application/json)
$client->asJson();
// Form URL-encoded (Content-Type: application/x-www-form-urlencoded)
$client->asForm();
// Multipart (Content-Type: multipart/form-data)
$client->asMultipart();// Append query parameters to all requests
$client->withQuery([
'api_key' => 'abc123',
'format' => 'json',
]);
// Combined with path: /users?api_key=abc123&format=json
$client->get('/users');$client->userAgent('MyApp/1.0');// Retry up to 3 times with 1000ms delay between attempts
$client->retry(times: 3, sleepMs: 1000);Retries are triggered on connection failures and 5xx server errors.
// Set arbitrary cURL options
$client->withCurlOption(CURLOPT_FOLLOWLOCATION, true);
$client->withCurlOption(CURLOPT_MAXREDIRS, 5);$response = $client->get('/users');
$response = $client->get('/users', ['role' => 'admin']); // query params// JSON body (if asJson() is set)
$response = $client->post('/users', [
'name' => 'Alice',
'email' => 'alice@example.com',
]);
// Form body (if asForm() is set)
$response = $client->asForm()->post('/login', [
'username' => 'alice',
'password' => 'secret',
]);
// Multipart file upload
$response = $client->asMultipart()->post('/upload', [
'file' => new \CURLFile('/path/to/photo.jpg', 'image/jpeg', 'photo.jpg'),
'description' => 'Profile photo',
]);$response = $client->put('/users/42', ['name' => 'Alice Updated']);
$response = $client->patch('/users/42', ['name' => 'Alice Patched']);
$response = $client->delete('/users/42');$response = $client->head('/health');
$response = $client->options('/users');$response = $client->send('GET', '/custom-endpoint', [
'key' => 'value',
]);All HTTP methods return an HttpResponse object.
$response->status(); // 200
// Boolean helpers
$response->successful(); // 2xx
$response->ok(); // 200
$response->failed(); // 4xx or 5xx
$response->redirect(); // 3xx
$response->clientError(); // 4xx
$response->serverError(); // 5xx// Raw body
$html = $response->body();
// Decode JSON
$data = $response->json();
// ['users' => [['id' => 1, 'name' => 'Alice'], ...]]
// Dot-notation access into JSON
$name = $response->jsonGet('users.0.name');
// 'Alice'// All headers
$headers = $response->headers();
// Single header
$type = $response->header('Content-Type');
// 'application/json; charset=utf-8'
// Check if header exists
$response->hasHeader('X-Rate-Limit');
// Content type shorthand
$response->contentType();
// 'application/json; charset=utf-8'// Throw HttpException on failure (4xx/5xx)
$response->throw();
// Conditional throw
$response->throwIf($response->status() === 422);
// The exception wraps the response object
try {
$response->throw();
} catch (\Razy\Http\HttpException $e) {
echo $e->getCode(); // HTTP status code (e.g., 404)
echo $e->getMessage(); // Error message
$resp = $e->response; // Original HttpResponse
$body = $resp->json(); // Access response body
}$array = $response->toArray();
// ['status' => 200, 'headers' => [...], 'body' => '...']Register callbacks for request/response lifecycle:
$client->beforeSending(function (array &$options) {
// Modify cURL options before the request
$options[CURLOPT_VERBOSE] = true;
// Log outgoing request
Log::debug('HTTP Request', $options);
});
$client->afterResponse(function (HttpResponse $response) {
// Log response
Log::debug('HTTP Response', [
'status' => $response->status(),
'body' => substr($response->body(), 0, 500),
]);
// Rate limit tracking
if ($response->hasHeader('X-Rate-Limit-Remaining')) {
RateTracker::update((int) $response->header('X-Rate-Limit-Remaining'));
}
});use Razy\Http\HttpClient;
class GitHubClient
{
private HttpClient $http;
public function __construct(string $token)
{
$this->http = HttpClient::create()
->baseUrl('https://api.github.com')
->withToken($token)
->asJson()
->withHeaders([
'Accept' => 'application/vnd.github.v3+json',
'X-GitHub-Api-Version' => '2022-11-28',
])
->timeout(15)
->retry(times: 2, sleepMs: 1000);
}
public function getUser(string $username): array
{
return $this->http
->get("/users/{$username}")
->throw()
->json();
}
public function listRepos(string $username, int $page = 1): array
{
return $this->http
->get("/users/{$username}/repos", [
'page' => $page,
'per_page' => 30,
'sort' => 'updated',
])
->throw()
->json();
}
public function createIssue(string $owner, string $repo, string $title, string $body): array
{
return $this->http
->post("/repos/{$owner}/{$repo}/issues", [
'title' => $title,
'body' => $body,
])
->throw()
->json();
}
}
// Usage
$github = new GitHubClient('ghp_xxxxxxxxxxxx');
$user = $github->getUser('octocat');
$repos = $github->listRepos('octocat');| Method | Signature | Returns |
|---|---|---|
create |
(): static |
New instance |
baseUrl |
(string $url): static |
Set base URL |
withHeaders |
(array $headers): static |
Set multiple headers |
withHeader |
(string $name, string $value): static |
Set single header |
withToken |
(string $token): static |
Bearer auth |
withBasicAuth |
(string $user, string $pass): static |
Basic auth |
timeout |
(int $seconds): static |
Request timeout |
connectTimeout |
(int $seconds): static |
Connect timeout |
withoutVerifying |
(): static |
Disable SSL verify |
asJson |
(): static |
JSON content type |
asForm |
(): static |
Form content type |
asMultipart |
(): static |
Multipart content type |
withQuery |
(array $params): static |
Default query params |
userAgent |
(string $ua): static |
User-Agent header |
retry |
(int $times, int $sleepMs): static |
Retry config |
withCurlOption |
(int $opt, mixed $val): static |
cURL option |
beforeSending |
(Closure $cb): static |
Pre-request hook |
afterResponse |
(Closure $cb): static |
Post-response hook |
get |
(string $url, array $query = []): HttpResponse |
GET request |
post |
(string $url, array $data = []): HttpResponse |
POST request |
put |
(string $url, array $data = []): HttpResponse |
PUT request |
patch |
(string $url, array $data = []): HttpResponse |
PATCH request |
delete |
(string $url, array $data = []): HttpResponse |
DELETE request |
head |
(string $url): HttpResponse |
HEAD request |
options |
(string $url): HttpResponse |
OPTIONS request |
send |
(string $method, string $url, array $data = []): HttpResponse |
Generic request |
| Method | Signature | Returns |
|---|---|---|
status |
(): int |
HTTP status code |
successful |
(): bool |
2xx? |
ok |
(): bool |
200? |
failed |
(): bool |
4xx or 5xx? |
redirect |
(): bool |
3xx? |
clientError |
(): bool |
4xx? |
serverError |
(): bool |
5xx? |
body |
(): string |
Raw body |
json |
(): mixed |
JSON decoded |
jsonGet |
(string $dotPath): mixed |
Dot-notation access |
headers |
(): array |
All headers |
header |
(string $name): ?string |
Single header |
hasHeader |
(string $name): bool |
Header exists? |
contentType |
(): ?string |
Content-Type |
throw |
(): static |
Throw on failure |
throwIf |
(bool $condition): static |
Conditional throw |
toArray |
(): array |
Serialise |
| Property | Type | Description |
|---|---|---|
response |
HttpResponse |
Original response |
| Code | int |
HTTP status code |
Extends \RuntimeException.