The Instructor HTTP client API provides a flexible and consistent way to create and send HTTP requests across different client implementations. This chapter covers the details of building and customizing HTTP requests.

Creating Requests

All HTTP requests are created using the HttpRequest class, which encapsulates the various components of an HTTP request.

Basic Request Creation

The constructor for HttpRequest takes several parameters:
use Cognesy\Http\Data\HttpRequest;

$request = new HttpRequest(
    url: 'https://api.example.com/endpoint',
    method: 'GET',
    headers: ['Accept' => 'application/json'],
    body: [],
    options: []
);
// @doctest id="4ae3"
The parameters are:
  • url: The URL to send the request to (string)
  • method: The HTTP method to use (string)
  • headers: An associative array of HTTP headers (array)
  • body: The request body, which can be a string or an array (mixed)
  • options: Additional options for the request (array)

Request Methods

Once you’ve created a request, you can access its properties using the following methods:
// Get the request URL
$url = $request->url();

// Get the HTTP method
$method = $request->method();

// Get the request headers
$headers = $request->headers();

// Get the request body
$body = $request->body();

// Get the request options
$options = $request->options();

// Check if the request is configured for streaming
$isStreaming = $request->isStreamed();
// @doctest id="b31f"

Modifying Requests

You can also modify a request after it’s been created:
// Enable streaming for this request
$streamingRequest = $request->withStreaming(true);
// @doctest id="9e99"
Note that the with* methods return a new request instance rather than modifying the original one.

HTTP Methods

The HTTP method is specified as a string in the HttpClientRequest constructor. The library supports all standard HTTP methods:

GET Requests

GET requests are used to retrieve data from a server:
$getRequest = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'GET',
    headers: ['Accept' => 'application/json'],
    body: [],
    options: []
);
// @doctest id="c0d0"
For GET requests with query parameters, include them in the URL:
$getRequestWithParams = new HttpRequest(
    url: 'https://api.example.com/users?page=1&limit=10&sort=name',
    method: 'GET',
    headers: ['Accept' => 'application/json'],
    body: [],
    options: []
);
// @doctest id="da99"

POST Requests

POST requests are used to create new resources or submit data:
$postRequest = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'POST',
    headers: [
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
    body: [
        'name' => 'John Doe',
        'email' => 'john@example.com',
    ],
    options: []
);
// @doctest id="892b"

PUT Requests

PUT requests are used to update existing resources:
$putRequest = new HttpRequest(
    url: 'https://api.example.com/users/123',
    method: 'PUT',
    headers: [
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
    body: [
        'name' => 'John Updated',
        'email' => 'john.updated@example.com',
    ],
    options: []
);
// @doctest id="bae7"

PATCH Requests

PATCH requests are used to partially update resources:
$patchRequest = new HttpRequest(
    url: 'https://api.example.com/users/123',
    method: 'PATCH',
    headers: [
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
    body: [
        'email' => 'new.email@example.com',
    ],
    options: []
);
// @doctest id="5a75"

DELETE Requests

DELETE requests are used to remove resources:
$deleteRequest = new HttpRequest(
    url: 'https://api.example.com/users/123',
    method: 'DELETE',
    headers: ['Accept' => 'application/json'],
    body: [],
    options: []
);
// @doctest id="2f29"

Other Methods

The library also supports other HTTP methods like HEAD, OPTIONS, etc. Just specify the method name as a string:
$headRequest = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'HEAD',
    headers: [],
    body: [],
    options: []
);

$optionsRequest = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'OPTIONS',
    headers: [],
    body: [],
    options: []
);
// @doctest id="81fd"

Setting Headers

HTTP headers are specified as an associative array where keys are header names and values are header values:
$request = new HttpRequest(
    url: 'https://api.example.com/data',
    method: 'GET',
    headers: [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer ' . $apiToken,
        'User-Agent' => 'MyApp/1.0',
        'X-Custom-Header' => 'Custom Value',
    ],
    body: [],
    options: []
);
// @doctest id="5e39"

Common Headers

Some commonly used HTTP headers include:
  • Content-Type: Specifies the format of the request body
'Content-Type' => 'application/json'
// @doctest id="a316"
  • Accept: Indicates what response format the client can understand
'Accept' => 'application/json'
// @doctest id="2fcc"
  • Authorization: Provides authentication credentials
'Authorization' => 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
// @doctest id="4b03"
  • User-Agent: Identifies the client application
'User-Agent' => 'MyApp/1.0 (https://example.com)'
// @doctest id="04e9"
  • Cache-Control: Directives for caching mechanisms
'Cache-Control' => 'no-cache'
// @doctest id="6dd6"
  • Accept-Language: Indicates the preferred language
'Accept-Language' => 'en-US,en;q=0.9'
// @doctest id="6d30"

Request Body

The request body can be provided in two ways:

Array Body (JSON)

If you provide an array as the request body, it will automatically be converted to a JSON string:
$request = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'POST',
    headers: ['Content-Type' => 'application/json'],
    body: [
        'name' => 'John Doe',
        'email' => 'john@example.com',
        'age' => 30,
        'address' => [
            'street' => '123 Main St',
            'city' => 'Anytown',
            'zipcode' => '12345',
        ],
        'tags' => ['developer', 'php'],
    ],
    options: []
);
// @doctest id="ab87"
When using an array for the body, you should set the Content-Type header to application/json.

String Body

You can also provide the body as a raw string:
// JSON string
$jsonBody = json_encode([
    'name' => 'John Doe',
    'email' => 'john@example.com',
]);

$request = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'POST',
    headers: ['Content-Type' => 'application/json'],
    body: $jsonBody,
    options: []
);
// @doctest id="1531"
This approach is useful for other content types:
// Form URL-encoded data
$formBody = http_build_query([
    'name' => 'John Doe',
    'email' => 'john@example.com',
]);

$request = new HttpRequest(
    url: 'https://api.example.com/users',
    method: 'POST',
    headers: ['Content-Type' => 'application/x-www-form-urlencoded'],
    body: $formBody,
    options: []
);
// @doctest id="46a5"

Working with Request Body

The body is managed by the HttpRequestBody class, which provides methods to access the body in different formats:
// Get the body as a string
$bodyString = $request->body()->toString();

// Get the body as an array (for JSON bodies)
$bodyArray = $request->body()->toArray();
// @doctest id="7a0f"

Request Options

The options parameter allows you to specify additional options for the request:
$request = new HttpRequest(
    url: 'https://api.example.com/data',
    method: 'GET',
    headers: [],
    body: [],
    options: [
        'stream' => true,  // Enable streaming response
    ]
);
// @doctest id="b64a"

Available Options

Currently, the main supported option is:
  • stream: When set to true, enables streaming response handling
You can check if a request is configured for streaming:
if ($request->isStreamed()) {
    // Handle streaming response
}
// @doctest id="243c"

Example: Streaming Request

Here’s how to create a request for a streaming API:
$streamingRequest = new HttpRequest(
    url: 'https://api.openai.com/v1/completions',
    method: 'POST',
    headers: [
        'Content-Type' => 'application/json',
        'Authorization' => 'Bearer ' . $apiKey,
    ],
    body: [
        'model' => 'text-davinci-003',
        'prompt' => 'Once upon a time',
        'max_tokens' => 100,
        'stream' => true,
    ],
    options: [
        'stream' => true, // Enable streaming in the client
    ]
);
// @doctest id="e98b"
In the following chapters, we’ll explore how to handle responses, including streaming responses, and how to use more advanced features like request pools and middleware.