-
Notifications
You must be signed in to change notification settings - Fork 0
HttpClient
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.
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.