HTTP Client

Overview

The HttpClient class provides a clean cURL-based HTTP client for making outgoing requests from your application. It supports all HTTP methods, JSON and form-encoded bodies, custom headers, redirect following, timeouts, and always returns a consistent response array — never false.

  • Class: JiFramework\Core\Network\HttpClient
  • Access: $app->http

Features at a glance:

  • GET, POST, and generic method support — get(), post(), request()
  • Form-encoded and JSON request bodies
  • Custom request headers
  • Response headers included in every return value
  • Automatic redirect following (configurable)
  • Per-request timeouts — total and connection
  • Consistent return structure — always [status_code, body, headers, error]
  • SSL verification enabled by default, opt-out available
$app = new App();

// GET request
$r = $app->http->get('https://api.example.com/users');

// POST with JSON body
$r = $app->http->post('https://api.example.com/users', [
    'name' => 'Alice',
    'email' => '[email protected]',
], ['json' => true]);

echo $r['status_code']; // 201
echo $r['body'];        // raw response body string

Response Structure

All three methods return the same associative array regardless of whether the request succeeded or failed. You never need to check for false.

  • status_code(int) HTTP status code (200, 404, 500, etc.). 0 when a cURL-level error occurs before a response is received.
  • body(string) Raw response body. Empty string on cURL error.
  • headers(array) Response headers as a map of lowercase header name to an array of values, e.g. ['content-type' => ['application/json']].
  • error(string|null) null on success. The cURL error message string on failure (e.g. timeout, DNS failure, SSL error).
$r = $app->http->get('https://api.example.com/products');

// Always safe to read these keys — no null checks needed
echo $r['status_code'];        // 200
echo $r['body'];               // raw JSON string
echo $r['headers']['content-type'][0]; // "application/json"
var_dump($r['error']);         // NULL

// Check for success
if ($r['error'] !== null) {
    // cURL-level failure (timeout, DNS, SSL, etc.)
    error_log('Request failed: ' . $r['error']);
} elseif ($r['status_code'] !== 200) {
    // Server responded with an error status
    error_log('HTTP ' . $r['status_code']);
} else {
    $data = json_decode($r['body'], true);
}

get()

get(string $url, array $options = []): array

Performs an HTTP GET request. Query parameters should be appended to the URL directly or built with http_build_query().

  • $url(string) The full URL to request.
  • $options(array, optional) Request options. See the Options section for all supported keys.
$http = $app->http;

// Basic GET
$r = $http->get('https://api.example.com/users');

// With query parameters
$r = $http->get('https://api.example.com/users?' . http_build_query([
    'page'  => 2,
    'limit' => 20,
]));

// With custom header and timeout
$r = $http->get('https://api.example.com/me', [
    'headers' => ['Authorization: Bearer ' . $token],
    'timeout' => 10,
]);

if ($r['error'] === null && $r['status_code'] === 200) {
    $user = json_decode($r['body'], true);
}

post()

post(string $url, array $data = [], array $options = []): array

Performs an HTTP POST request. Body is form-encoded by default. Pass 'json' => true in options to send a JSON body instead.

  • $url(string) The full URL to request.
  • $data(array, optional) Body data to send with the request.
  • $options(array, optional) Request options. See the Options section for all supported keys.

Form-encoded body — the default. Sends data as application/x-www-form-urlencoded.

$r = $app->http->post('https://api.example.com/login', [
    'username' => 'alice',
    'password' => 'secret',
]);

if ($r['status_code'] === 200) {
    $result = json_decode($r['body'], true);
}

JSON body — set 'json' => true in options. The Content-Type: application/json header is added automatically unless you provide your own.

$r = $app->http->post('https://api.example.com/users', [
    'name'  => 'Alice',
    'email' => '[email protected]',
    'role'  => 'editor',
], ['json' => true]);

// $r['status_code'] => 201
// $r['body']        => raw JSON response

request()

request(string $method, string $url, array $data = [], array $options = []): array

Performs a request with any HTTP method. Use this for PUT, PATCH, DELETE, and any other verb. The method name is case-insensitive.

  • $method(string) HTTP method (e.g. PUT, PATCH, DELETE). Case-insensitive.
  • $url(string) The full URL to request.
  • $data(array, optional) Body data. Form-encoded by default; JSON if 'json' => true is set in options.
  • $options(array, optional) Request options. See the Options section for all supported keys.
$http = $app->http;

// PUT — replace a resource
$r = $http->request('PUT', 'https://api.example.com/users/42', [
    'name'  => 'Alice Updated',
    'email' => '[email protected]',
], ['json' => true]);

// PATCH — partial update
$r = $http->request('PATCH', 'https://api.example.com/users/42', [
    'name' => 'Alice Renamed',
], ['json' => true]);

// DELETE — no body needed
$r = $http->request('DELETE', 'https://api.example.com/users/42');

if ($r['status_code'] === 204 || $r['status_code'] === 200) {
    // deleted successfully
}

Options Reference

All three methods accept an $options array as their last parameter. All keys are optional.

  • headers(array) Custom HTTP request headers. Each entry is a raw header string: ['Authorization: Bearer token', 'Accept: application/json'].
  • json(bool) When true, encodes the request body as JSON and automatically adds Content-Type: application/json unless already present in headers. Default: false.
  • timeout(int) Maximum total time in seconds for the request to complete (CURLOPT_TIMEOUT). No limit by default.
  • connect_timeout(int) Maximum time in seconds to wait for the connection to be established (CURLOPT_CONNECTTIMEOUT). No limit by default.
  • follow_redirects(bool) Whether to follow HTTP 301/302 redirects automatically. Default: true. Up to 10 redirects are followed.
  • ssl_verify(bool) Whether to verify the SSL certificate and host. Default: true. Set to false only in development against self-signed certificates.
$r = $app->http->post('https://api.example.com/data', $payload, [
    'json'            => true,
    'headers'         => ['Authorization: Bearer ' . $token],
    'timeout'         => 30,
    'connect_timeout' => 5,
    'follow_redirects'=> true,
    'ssl_verify'      => true,
]);

Working with Responses

Common patterns for handling the response array returned by all three methods.

Decoding a JSON API response:

$r = $app->http->get('https://api.example.com/products', [
    'headers' => ['Accept: application/json'],
]);

if ($r['error'] !== null) {
    // Network-level failure — log and bail
    $app->logger->error('HTTP request failed: {error}', ['error' => $r['error']]);
    $app->abort(503, 'Could not reach external API');
}

if ($r['status_code'] !== 200) {
    $app->abort($r['status_code']);
}

$products = json_decode($r['body'], true);

Reading response headers:

$r = $app->http->get('https://api.example.com/resource');

// Headers are lowercase, values are arrays
$contentType = $r['headers']['content-type'][0] ?? null;
$rateLimit   = $r['headers']['x-ratelimit-remaining'][0] ?? null;

Downloading with a short timeout:

$r = $app->http->get($webhookUrl, [
    'timeout'         => 5,
    'connect_timeout' => 2,
]);

if ($r['error'] !== null) {
    // Timeout or connection refused — handle gracefully
}

Calling an API that uses self-signed SSL (dev only):

$r = $app->http->get('https://local.dev/api/ping', [
    'ssl_verify' => false,
]);

setDebug()

setDebug(bool $debug): void

Enables cURL verbose output and prints the response array after each request. Useful for debugging connection issues during development. Disable in production.

  • $debug(bool) true to enable, false to disable.
$http = $app->http;
$http->setDebug(true);

$r = $http->get('https://api.example.com/users');
// cURL verbose output printed to the page/CLI
// Response array also printed via print_r()

$http->setDebug(false); // turn off for subsequent requests

Debug mode prints the cURL negotiation (SSL handshake, redirects, headers sent and received) to standard output. Only enable this during local development — it will expose sensitive header values including auth tokens on screen.